Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 两个线程完成执行后的清理_Java_Multithreading_Synchronization - Fatal编程技术网

Java 两个线程完成执行后的清理

Java 两个线程完成执行后的清理,java,multithreading,synchronization,Java,Multithreading,Synchronization,我有一个运行作业的应用程序,每个作业需要两个线程。这两个线程通常会做一些工作,并在彼此之后不久完成。然后,在第二个线程完成后,我需要进行一些清理,但由于线程正在执行一些网络IO,一个线程可能会被阻塞很长时间。在这种情况下,我希望清理在第一个线程完成几秒钟后进行 我在回调类中使用以下代码段实现了此行为: private boolean first = true; public synchronized void done() throws InterruptedException { i

我有一个运行作业的应用程序,每个作业需要两个线程。这两个线程通常会做一些工作,并在彼此之后不久完成。然后,在第二个线程完成后,我需要进行一些清理,但由于线程正在执行一些网络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秒,但在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选项允许任何一个线程先完成。太好了,看起来这正是我需要的,没有等待()和通知()。缺点是更多的代码和额外的线程,但我想你不可能拥有全部;)