我有一个班级 start()
以及 stop()
方法并希望执行以下操作:
1其中一个方法不能在另一个正在运行时调用,例如 start()
那就叫什么 stop()
不能同时调用。
2a调用已经运行的方法时,应该立即跳过,
2b或者它们应该在初始调用(拥有锁)返回的同时返回。
我认为第一个要求可以通过添加 synchronized
阻止。要求2a可能很适合 AtomicBoolean
. 然而,对我来说,这看起来比它应该是复杂的。还有其他可能性吗?是否有一个类可以一次性满足这两个要求?我真的不知道2b是怎么实现的。
当我重新阅读示例代码时,我意识到 synchronized
可能需要在 isStarted
检查。但是,当调用已经在方法中时,我无法立即返回。另一方面,对于下面给出的代码,我不能阻止一个线程进行比较和设置 isStarted
至 true
然后挂起另一个线程 stop()
尽管 start()
逻辑尚未完成。
示例代码
private final AtomicBoolean isStarted = new AtomicBoolean(false);
private final Object lock = new Object();
public void start() {
if (isStarted.compareAndSet(false, true)) {
synchronized(lock) {
// start logic
}
} else {
log.warn("Ignored attempt to start()");
}
}
public void stop() {
if (isStarted.compareAndSet(true, false)) {
synchronized(lock) {
// stop logic
}
} else {
log.warn("Ignored attempt to stop()");
}
}
2条答案
按热度按时间mbskvtky1#
您的代码可以实现如下的双重检查:
这应该符合你的所有条件1,2a,2b。如果您公开isstarted,您可以在操作(do start/do stop)完成之后而不是之前修改标志,但是在这种情况下2b会频繁发生。
但是,在现实生活中,我更喜欢在线程之间使用消息传递,而不是使用容易导致死锁的锁(例如,您在锁下通知一些侦听器,侦听器使用自己的锁)。
简单的阻塞队列可以是这样的消息传递队列。一个线程使用队列中的所有命令,并根据其当前状态(现在不是共享状态)逐个执行它们(在其run()方法中)。另一个线程将启动/停止命令放入队列。
y1aodyip2#
让我们想象一下这个场景:
线程a进入“start”。
线程a正忙着,试图挖掘“开始”逻辑。这需要一段时间。
当a仍然忙时,因此代码的状态是“starting in progress”,而不是“i have start”,线程b也会调用start。
你说b马上回来你没问题。
我怀疑你是不是真的那么想;这意味着b中的代码调用“start”,然后这个调用返回,但是对象还没有处于“started”状态。当然,只有当对象实际处于“running”状态时,才能正常返回对start()的调用,如果不可能,则通过exception返回。
既然我正确地解释了你的需求,那就忘掉布尔值吧;你所需要的就是同步。记住,锁是api的一部分,java中没有公共字段,所以你不应该拥有公共锁,除非你做了大量的文档记录(并且考虑到你的代码与锁交互的方式是公共api的一部分,你不能在不破坏向后兼容性的情况下修改它-通常你不想随便地给出一个承诺,因为这对将来的更新来说是一副手铐),所以,你的想法,使私人锁领域是伟大的。但是,我们已经有了一个私有的唯一示例,我们可以将其重新用于锁:
此代码将确保调用'start();'将保证代码在正常返回时处于“started”状态,或者至少是处于“started”状态(一个例外是如果其他线程正在等待停止它,并且在线程启动后立即停止;想必,奇怪的是,不管是什么状态导致stop()运行,都希望发生这种情况)。
此外,如果希望锁定行为成为此类api的一部分,可以这样做。例如,您可以添加: