简体   繁体   English

Java - 每个线程有多个 Runnables

[英]Java - multiple Runnables per Thread

I got a fixed number of threads.我有固定数量的线程。 I want each thread to run three Runnable s, one after another.我希望每个线程一个接一个地运行三个Runnable Here's some pseudocode to explain:这里有一些伪代码来解释:

Thread[] threads = new Thread[4];

for (int i = 0; i < threads.length; i++) {
    // Set the first tasks.
    threads[i] = new Thread(new FirstRunnable());
    threads[i].start();
}

for (int i = 0; i < threads.length; i++)
    threads[i].join(); // wait until the first tasks are done

for (int i = 0; i < threads.length; i++) {
    // Set the second task.
    threads[i].setRunnable(new SecondRunnable());
    threads[i].start();
}

for (int i = 0; i < threads.length; i++)
    threads[i].join(); // wait until the second tasks are done

...

Using a ThreadPool sounds way overkill, especially since I'm headed for performance, performance, performance.使用ThreadPool听起来有点矫枉过正,特别是因为我正在追求性能、性能、性能。 What's the best way to implement this in Java?在 Java 中实现此功能的最佳方法是什么?

Whenever you see new Thread(...).start() , make use of the Executors framework.每当您看到new Thread(...).start()时,请使用Executors框架。 In particular, make use of Executors.newFixedThreadPool(...) .特别是,利用Executors.newFixedThreadPool(...)

You can use a CyclicBarrier and a "CombinedRunnable" as shown below.您可以使用CyclicBarrier和“CombinedRunnable”,如下所示。 The barrier allows the threads to all wait for each other to finish, before proceeding to the next runnable.屏障允许线程在继续下一个可运行之前相互等待完成。

CyclicBarrier barrier = new CyclicBarrier(4);
Runnable r = new CombinedRunnable(barrier, new FirstRunnable(), new SecondRunnable());
Thread[] threads = new Thread[4];
for (int i = 0; i < threads.length; i++) {
    threads[i] = new Thread(r);
    threads[i].start();
}

The CombinedRunnable class: CombinedRunnable class:

public class CombinedRunnable implements Runnable{

    private final CyclicBarrier barrier;
    private final Runnable[] runnables;

    public CombinedRunnable(CyclicBarrier barrier, Runnable... runnables){
        this.barrier = barrier;
        this.runnables = runnables;
    }

    /* (non-Javadoc)
     * @see java.lang.Runnable#run()
     */
    @Override
    public void run() {
        for(Runnable r: runnables){
            r.run();
            try {
                barrier.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
        }
    }
}

Seems like a good use for a newFixedThreadPool from the Executors class. Executors class 的 newFixedThreadPool 似乎很好用。

So your code would look something like:所以你的代码看起来像:

ExecutorService es = Executors.newFixedThreadPool(4);
List<Future> futures = new ArrayList<Future>();
for (int x = 0; x < 4; x ++) {
    futures.add(es.submit(new FirstRunnable()));
}
while (futures.size() > 0) {
   futures.remove(0).get();
}
for (int x = 0; x < 4; x ++) {
    futures.add(es.submit(new SecondRunnable()));
}

while (futures.size() > 0) {
   futures.remove(0).get();
}

Of course, you could probably easily refactor the code above to remove code duplication.当然,您可以轻松地重构上面的代码以消除代码重复。

An idiomatic way to achieve this is by using an Executor in conjunction with a CompletionService .实现此目的的惯用方法是将ExecutorCompletionService结合使用。 This allows you to map many units of work to a fixed size pool of threads and also provides an elegant mechanism for blocking until all work is complete.这允许您将许多工作单元分配到固定大小的线程池中,并且还提供了一种优雅的阻塞机制,直到所有工作完成。

Note that your concern about how using a thread pool might impact efficiency is not really an issue: The main overhead is in creating individual threads, which you were doing anyway;请注意,您对使用线程池可能会如何影响效率的担忧并不是真正的问题:主要开销是创建单个线程,无论如何您都在这样做; the additional object creation overhead in creating a pool will be negligible.创建池时额外的 object 创建开销可以忽略不计。

// Create fixed thread pool and wrap in a CompletionService to allow for easy access to completed tasks.
// We don't have an explicit result for each Runnable so parameterise the service on Void.
CompletionService<Void> cs = new ExecutorCompletionService<Void>(Executors.newFixedThreadPool(3));

// Create units of work for submission to completion service.
Runnable[] runnables = ...

// Submit runnables.  Note that we don't care about the result so pass in null.
for (Runnable r : runnables) {
  cs.submit(r, null);
}

// Take each *completed* result in turn, blocking until a completed result becomes available.
for (int i=0; i<runnables.length; ++i) {
  Future<Void> completed = cs.take();
}

Executor Framework is just for you. Executor Framework 只适合你。
Here's the pseudocode:这是伪代码:
1. Create executor service 1.创建执行器服务

Executors type1Runnables = Executors.newFixedThreadPool(4);
Executors type2Runnables = Executors.newFixedThreadPool(4);

etc.. ETC..
2. Submit tasks to it 2.向它提交任务

for(){
type1Runnables.submit(new Runnable1());
type2Runnables.submit(new Runnable2);
}

3. Invoke the executors 3. 调用执行者

type1Runnables.invokeAll();
type2Runnables.invokeAll();

To make it more generic you could perhaps write your own executorservicefactory which accepts the different runnable types.为了使其更通用,您也许可以编写自己的 executorservicefactory 接受不同的可运行类型。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM