[英]Cleaning up after two threads finish execution
我有一個運行作業的應用程序,每個作業需要兩個線程。 這兩個線程通常會做一些工作並且很快就會完成。 然后在第二個線程完成之后我需要做一些清理,但由於線程正在做一些網絡IO,因此一個線程可能會被阻塞很長時間。 在這種情況下,我希望在第一個線程完成后幾秒鍾進行清理。
我在回調類中使用以下代碼實現了此行為:
private boolean first = true;
public synchronized void done() throws InterruptedException {
if (first) {
first = false;
wait(3000);
// cleanup here, as soon as possible
}
else {
notify();
}
}
兩個線程在完成時都會調用done()方法。 然后第一個將在wait()中阻塞最多3秒,但是當秒線程調用done()方法時將立即通知。
我已經測試了這個實現,它似乎運行良好,但我很好奇是否有更好的方法來做到這一點。 雖然這個實現看起來並不太復雜,但我擔心我的程序會死鎖或者有一些意想不到的同步問題。
由於done
方法是同步的,因此一次只能執行一個線程,第二個線程將等待發送notify直到第一次完成整個作業,這可能會導致性能瓶頸。
我寧願用短的同步塊來設計它,這將首先主要更新boolean first
。
我希望我明白你的需要。 你想等待thread-a完成然后等待3秒或者等待thread-b的結束。
最好使用較新的Concurrent
工具而不是舊的wait/notify
因為它們有很多邊緣情況。
// Two threads running so count down from 2.
CountDownLatch wait = new CountDownLatch(2);
class TestRun implements Runnable {
private final long waitTime;
public TestRun(long waitTime) {
this.waitTime = waitTime;
}
@Override
public void run() {
try {
// Wait a few seconds.
Thread.sleep(waitTime);
// Finished! Count me down.
wait.countDown();
System.out.println(new Date() + ": " + Thread.currentThread().getName() + " - Finished");
} catch (InterruptedException ex) {
System.out.println(Thread.currentThread().getName() + " - Interrupted");
}
}
}
public void test() throws InterruptedException {
// ThreadA
Thread threadA = new Thread(new TestRun(10000), "Thread A");
// ThreadB
Thread threadB = new Thread(new TestRun(30000), "Thread B");
// Fire them up.
threadA.start();
threadB.start();
// Wait for all to finish but threadA must finish.
threadA.join();
// Wait up to 3 seconds for B.
wait.await(3, TimeUnit.SECONDS);
System.out.println(new Date() + ": Done");
threadB.join();
}
愉快地打印:
Tue Sep 15 16:59:37 BST 2015: Thread A - Finished
Tue Sep 15 16:59:40 BST 2015: Done
Tue Sep 15 16:59:57 BST 2015: Thread B - Finished
添加
隨着新的清晰度 - 任何線程的結束啟動計時器 - 我們可以使用第三個線程進行清理。 每個線程在完成時都必須調用一個方法來觸發清理機制。
// Two threads running so count down from 2.
CountDownLatch wait = new CountDownLatch(2);
class TestRun implements Runnable {
private final long waitTime;
public TestRun(long waitTime) {
this.waitTime = waitTime;
}
@Override
public void run() {
try {
// Wait a few seconds.
Thread.sleep(waitTime);
// Finished! Count me down.
wait.countDown();
System.out.println(new Date() + ": " + Thread.currentThread().getName() + " - Finished");
// Record that I've finished.
finished();
} catch (InterruptedException ex) {
System.out.println(Thread.currentThread().getName() + " - Interrupted");
}
}
}
Runnable cleanup = new Runnable() {
@Override
public void run() {
try {
// Wait up to 3 seconds for both threads to clear.
wait.await(3, TimeUnit.SECONDS);
// Do your cleanup stuff here.
// ...
System.out.println(new Date() + ": " + Thread.currentThread().getName() + " - Finished");
} catch (InterruptedException ex) {
System.out.println(Thread.currentThread().getName() + " - Interrupted");
}
}
};
final AtomicBoolean cleanupStarted = new AtomicBoolean(false);
private void finished() {
// Make sure I only start the cleanup once.
if (cleanupStarted.compareAndSet(false, true)) {
new Thread(cleanup, "Cleanup").start();
}
}
public void test() throws InterruptedException {
// ThreadA
Thread threadA = new Thread(new TestRun(10000), "Thread A");
// ThreadB
Thread threadB = new Thread(new TestRun(30000), "Thread B");
// Fire them up.
threadA.start();
threadB.start();
System.out.println(new Date() + ": Done");
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.