我有一个在单独的线程中初始化的对象。在填充本地数据库时,初始化可能需要几秒钟。
SpecialAnalysis currentAnalysis = new SpecialAnalysis(params_here);
我试图实施"取消"按钮,用于将对象的isCancelled
布尔值设置为true。实现这个的正确Java方法是什么?
while (currentAnalysis == null) {
}
currentAnalysis.cancel();
此方法冻结程序,因为它似乎已进入计算效率低下的循环。这是我可以使用Object.wait()
吗?
我目前的糟糕/半成功解决方案是:
while (currentAnalysis == null) {
Thread.sleep(500);
}
currentAnalysis.cancel();
谢谢!
答案 0 :(得分:7)
首先,是Object.wait()
和Object.notify()
/ Object.notifyAll()
是您所需要的。你是否直接使用它们是另一回事。由于使用wait/notify
直接编程容易出错,通常建议使用concurrency tools added in Java 1.5(请参阅下面的第二种方法)。
传统的wait/notify
方法:
初始化:
synchronized (lockObject) {
SpecialAnalysis currentAnalysis = new SpecialAnalysis(params_here);
lockObject.notifyAll();
}
取消'螺纹:
synchronized (lockObject) {
while (currentAnalysis == null) {
try { lockObject.wait(); }
catch Exception(e) { } // FIXME: ignores exception
}
}
currentAnalysis.cancel();
当然,这些可以是同步方法而不是块。您选择的lockObject
将取决于取消'取消'您需要的线程等。理论上它可以是任何东西,即Object lockObject = new Object();
,只要您小心正确的线程可以访问它。
请注意,由于spurious wakeups可能来自底层操作系统,因此在此处调用wait()
非常重要。
更简单的方法是使用CountDownLatch
,免除wait()
& notify()
的细节:
(我在这里做了几个假设,以便提出一个可能更清晰的方法)。
class AnalysisInitialiser extends Thread {
private CountDownLatch cancelLatch = new CountDownLatch(1);
private SpecialAnalysis analysis = null;
@Override
public void run() {
analysis = new SpecialAnalysis(params);
cancelLatch.countDown();
}
public SpecialAnalysis getAnalysis() {
cancelLatch.await();
return analysis;
}
}
然后在需要发送取消信号的线程中:(显然你需要以某种方式获取AnalysisInitialiser
对象)
analysisInit.getAnalysis.cancel();
没有并发原语样板,耶!
答案 1 :(得分:-1)
我喜欢这个问题所以投票了。
你可以这样做
do {
if(currentAnalysis != null){
currentAnalysis.cancel();
}
}
while (currentAnalysis == null)
此处,do
一直在检查currentAnalysis
的价值,一旦not null
,cancel
执行looping
,其他人保持currentAnalysis
并检查{{1}}值。
这是我现在找到的一种更好的方法