4

我有一个包含以下(Java)代码的方法:

doSomeThings();
doSomeOtherThings();

doSomeThings()创建一些线程,每个线程只运行有限的时间。问题是我不想在所有启动的线程都完成doSomeOtherThings()之前被调用。doSomeThings()doSomeThings()还将调用可能启动新线程的方法等。我不想在doSomeOtherThings()所有这些线程完成之前执行。)

这是因为doSomeThings(),除其他外,将设置myObjectnull,而我不想在那个时候doSomeOtherThings()打电话。myObject.myMethod()myObjectnull

有没有做这种事情的一些标准方法(在Java中)?

4

6 回答 6

10

你可能想看看这个java.util.concurrent包。特别是,您可以考虑使用CountDownLatchas

package de.grimm.game.ui;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Main {

public static void main(String[] args) 
throws Exception {

    final ExecutorService executor = Executors.newFixedThreadPool(5);
    final CountDownLatch latch = new CountDownLatch(3);

    for( int k = 0; k < 3; ++k ) {

        executor.submit(new Runnable() {
            public void run() {
                // ... lengthy computation...
                latch.countDown();
            }
        });
    }

    latch.await();

    // ... reached only after all threads spawned have
    // finished and acknowledged so by counting down the
    // latch.

    System.out.println("Done");
}
}

显然,如果您事先知道分叉线程的数量,这种技术才有效,因为您需要使用该数字初始化锁存器。

另一种方法是使用条件变量,例如:

boolean done = false;

void functionRunInThreadA() {

    synchronized( commonLock ) {

        while( !done ) commonLock.wait();
    }

    // Here it is safe to set the variable to null
}

void functionRunInThreadB() {

    // Do something...

    synchronized( commonLock ) {
        done = true;
        commonLock.notifyAll();
    }
}

您可能需要添加异常处理 ( InteruptedException) 等。

于 2010-04-05T19:52:37.490 回答
6

看看Thread.join()方法。

我不清楚您的确切实现,但似乎 doSomeThings() 应该在返回之前等待子线程。

在 doSomeThings() 方法内部,通过调用 Thread.join() 方法等待线程。

当您创建一个线程并调用该线程的 join() 方法时,调用线程会一直等待,直到该线程对象终止。

例子:

// Create an instance of my custom thread class
MyThread myThread = new MyThread();
// Tell the custom thread object to run
myThread.start();
// Wait for the custom thread object to finish
myThread.join();
于 2010-04-05T19:45:57.407 回答
3

您正在寻找的是 executorservice 并使用期货 :)

请参阅http://java.sun.com/docs/books/tutorial/essential/concurrency/exinter.html

因此,基本上收集您提交给执行器服务的所有可运行文件的期货。循环所有期货并调用 get() 方法。这些将在相应的可运行对象完成后返回。

于 2010-04-05T19:54:42.903 回答
1

另一个有用的更强大的Synchronization Barrier 您可以使用它来执行与 CountdownLatch 类似的功能是CyclicBarrier。它的工作方式类似于 CountdownLatch,您必须知道有多少方(线程)正在使用,但它允许您重用屏障,就像每次都创建一个新的 CountdownLatch 实例一样。

我确实喜欢 momania 的使用 ExecutorService 的建议,收集期货并调用所有它们直到它们完成。

于 2010-04-05T21:12:39.450 回答
0

取决于你到底想在这里做什么。您主要关心的是动态确定由从内部调用的连续方法产生的各种线程doSomeThings()然后能够等到它们完成后再调用 的能力doSomeOtherThings()吗?或者有可能知道在编译时产生的线程?在后一种情况下,有许多解决方案,但基本上都涉及Thread.join()从创建它们的任何位置调用所有这些线程上的方法。

如果确实是前者,那么你最好使用ThreadGroup它的enumerate() 方法。如果您已将新线程正确添加到 ThreadGroup,这将为您提供由 doSomeThings() 生成的所有线程的数组。然后,您可以遍历返回数组中的所有线程引用,并在调用join() 之前调用主线程doSomeOtherThings()

于 2010-04-08T23:37:31.690 回答
0

另一种选择是让你的主线程休眠,并让它每隔一段时间检查一下其他线程是否已经完成。但是,我更喜欢 Dirk 和 Marcus Adams 的答案——为了完整起见,把它扔在这里。

于 2010-04-05T19:55:10.637 回答