Java 我可以用更好的方式连接线程吗?

Java 我可以用更好的方式连接线程吗?,java,multithreading,concurrency,Java,Multithreading,Concurrency,假设一个程序中有多个可运行实例,所有实例都由一个执行者实例调度。此外,假设我在某个时候需要等待这些可运行项的子集完成,然后再继续 我可以这样做的一种方法是: public abstract class Joinable implements Runnable { private final Semaphore finishedLock = new Semaphore(1); @Override public final void run() { try

假设一个程序中有多个可运行实例,所有实例都由一个执行者实例调度。此外,假设我在某个时候需要等待这些可运行项的子集完成,然后再继续

我可以这样做的一种方法是:

public abstract class Joinable implements Runnable {

    private final Semaphore finishedLock = new Semaphore(1);

    @Override
    public final void run() {
        try {
            finishedLock.acquireUninterruptibly();
            doWork();
        } finally {
            finishedLock.release();
        }
    }

    public abstract void doWork();

    public void join() {
        finishedLock.acquireUninterruptibly();
    }
}
然后,实现类可以简单地重写doWork(),而不是run(),以便定义在执行期间应该做什么

然后,连接过程将简单地如下所示:

void doStuff() {

    Executor executor = Executors.newCachedThreadPool();

    List<Joinable> joinables = new LinkedList<Joinable>();
    // Fill joinables with implementors of Joinable...

    List<Runnable> others = new LinkedList<Runnable>();
    // Fill others with implementors of Runnable...

    for(Joinable joinable : joinables) 
        executor.execute(joinable);

    for(Runnable runnable : others) 
        executor.execute(runnable);

    for(Joinable joinable : joinables) 
        joinable.join();

    // Continue, no matter what the threads in others are up to.
}
List<Future<?>> futures = new ArrayList<Future<?>>();
for(Joinable joinable : joinables) {
   // this submit returns a `Future`.
   futures.add(executor.submit(joinable));
}
// submit others to the executor _without_ adding to the futures list

for (Future<?> future : futures) {
    // this can throw ExecutionException which wraps exception thrown by task
    future.get();
}
void doStuff(){
Executor Executor=Executors.newCachedThreadPool();
List joineables=newlinkedlist();
//用Joinable的实现者填充Joinable。。。
List others=新建LinkedList();
//用Runnable的实现者填充其他人。。。
用于(可接合:可接合)
执行人。执行(可合并);
for(可运行:其他)
执行器。执行(可运行);
用于(可接合:可接合)
joinable.join();
//继续,不管其他线程在做什么。
}
这是解决这个问题的好方法(安全吗?),还是有更好的方法

这是解决这个问题的好方法吗(安全吗?)

这是不对的。您不能加入由
ExecutorService
执行的
Runnable
。如果要使用列表,请执行以下操作:

void doStuff() {

    Executor executor = Executors.newCachedThreadPool();

    List<Joinable> joinables = new LinkedList<Joinable>();
    // Fill joinables with implementors of Joinable...

    List<Runnable> others = new LinkedList<Runnable>();
    // Fill others with implementors of Runnable...

    for(Joinable joinable : joinables) 
        executor.execute(joinable);

    for(Runnable runnable : others) 
        executor.execute(runnable);

    for(Joinable joinable : joinables) 
        joinable.join();

    // Continue, no matter what the threads in others are up to.
}
List<Future<?>> futures = new ArrayList<Future<?>>();
for(Joinable joinable : joinables) {
   // this submit returns a `Future`.
   futures.add(executor.submit(joinable));
}
// submit others to the executor _without_ adding to the futures list

for (Future<?> future : futures) {
    // this can throw ExecutionException which wraps exception thrown by task
    future.get();
}

但是,如果您正在等待任务的子集,我看不到任何更好的方法来实现这一点。

您当前的解决方案不是线程安全的。不能保证执行器在调用
join
之前会调用
run
在您的
Joinable
上运行。因此,在某些情况下,主线程将在
Joinable
之前获得锁


可能的解决方案是使用一个
CountDownLatch
,如果您知道可连接的总数量
N
,则创建一个
CountDownLatch(N)
,并将其传递给每个实例。当每个连接完成时,让它调用
倒计时()
。主线程在闩锁上调用
await()
await()
在闩锁计数为0之前不会返回。

我知道,不幸的是,我需要稍微澄清一下这个问题:我不会看到同一执行器只调度了一种可运行实例的情况。比如说,我有12个一类的实例,还有6个另一类的实例,我只想等到前12个实例完成后再继续,不管其他6个实例当时的状态如何。在这种情况下,我不能使用等待终止。我已经添加了一些关于使用
submit(…)
method@chrsva返回的
Future
的详细信息。我也喜欢另一个答案,但选择了这个答案,因为它与我的项目的总体设计非常吻合。