Java 两个线程完成执行后的清理
我有一个运行作业的应用程序,每个作业需要两个线程。这两个线程通常会做一些工作,并在彼此之后不久完成。然后,在第二个线程完成后,我需要进行一些清理,但由于线程正在执行一些网络IO,一个线程可能会被阻塞很长时间。在这种情况下,我希望清理在第一个线程完成几秒钟后进行 我在回调类中使用以下代码段实现了此行为:Java 两个线程完成执行后的清理,java,multithreading,synchronization,Java,Multithreading,Synchronization,我有一个运行作业的应用程序,每个作业需要两个线程。这两个线程通常会做一些工作,并在彼此之后不久完成。然后,在第二个线程完成后,我需要进行一些清理,但由于线程正在执行一些网络IO,一个线程可能会被阻塞很长时间。在这种情况下,我希望清理在第一个线程完成几秒钟后进行 我在回调类中使用以下代码段实现了此行为: private boolean first = true; public synchronized void done() throws InterruptedException { i
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秒,但在seconds线程调用done()方法时会立即收到通知
我已经测试了这个实现,它似乎工作得很好,但我很好奇是否有更好的方法来实现这一点。尽管这个实现看起来不太复杂,但我担心我的程序会死锁或出现一些意想不到的同步问题 由于
done
方法是同步的,因此一次只能执行一个线程,而第二个线程将等待发送通知,直到第一个线程完成其整个工作,这可能会导致性能瓶颈
我宁愿使用shortsynchronized block来设计它,它主要是首先更新
布尔值 我希望我理解你的需要。您需要等待线程a完成,然后等待3秒或线程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");
}
线程1在其中时,线程2如何访问完成()。@nafas-wait
释放锁。@OldCurmudgeon ah lol是的,出于某种原因,我在考虑线程.睡眠(…)。我的坏…wait
会释放锁,以便在第一个线程调用wait
时第二个线程可以继续,如果我认为会出现争用条件,如果第二个线程在3秒钟后调用&首先也是为什么第一个线程要多调用3秒钟?同步方法中只能有一个正在运行的线程,因此不能存在争用条件。3秒是一个宽限期,允许第二个线程完成它正在做的事情,尽管通常情况下,线程应该在相互之后的几毫秒内完成。你没有明白,我说的是,如果第二个线程在第一个线程完成3秒的等待后到达第二个线程,该怎么办,第二个线程将等待,直到第一个线程释放对象锁。我更希望没有宽限期,因为这项工作几乎可以在没有时间的情况下完成。另外,如果这个线程开始执行耗时的任务,那么这个宽限期可能不合适。任何一个线程都可能先完成。我想在第二个线程完成后立即清理,但在第一个线程完成后不超过3秒。@Gert Jan-在这种情况下,使用while(wait.getCount()>1){thread.sleep(1000);}
-虽然不太漂亮,但应该可以工作。例如,谢谢,我将尝试使用倒计时闩锁
编写一个实现。使用睡眠不是一个好的选择,因为我真的需要尽快清理,睡眠会带来额外的延迟。@Gert Jan-Second选项允许任何一个线程先完成。太好了,看起来这正是我需要的,没有等待()和通知()。缺点是更多的代码和额外的线程,但我想你不可能拥有全部;)