简体   繁体   English

Java线程等待值

[英]Java Threads waiting value

I have the following situation: 我有以下情况:

In order to run a algorithm, i must run several threads and each thread will set a instance variable x, right before it dies. 为了运行算法,我必须运行多个线程,并且每个线程都会在死之前设置一个实例变量x。 The problem is that these threads dont return immediately: 问题是这些线程不会立即返回:

public Foo myAlgorithm()
{
    //create n Runnables (n is big)
    //start these runnables (may take long time do die)

    //i need the x value of each runnable here, but they havent finished yet!

    //get average x from all the runnables

    return new Foo(averageX);
}

Should i use wait notify ? 我应该使用等待通知吗? Or should i just embed a while loop and check for termination ? 还是我应该嵌入一个while循环并检查是否终止?

Thanks everyone! 感谢大家!

Create some shared storage to hold the x value from each thread, or just store the sum if that's sufficient. 创建一些共享存储来保存每个线程的x值,或者只要足够就存储和。 Use a CountDownLatch to wait for the threads to terminate. 使用CountDownLatch等待线程终止。 Each thread, when finished, would call CountDownLatch.countDown() and your myAlgorithm method would use the CountDownLatch.await() method to wait for them. 每个线程完成后将调用CountDownLatch.countDown()而您的myAlgorithm方法将使用CountDownLatch.await()方法来等待它们。

Edit: Here's a complete example of the approach I suggested. 编辑:这是我建议的方法的完整示例。 It created 39 worker threads, each of which adds a random number to a shared sum. 它创建了39个工作线程,每个工作线程都将一个随机数添加到一个共享总和中。 When all of the workers are finished, the average is computed and printed. 当所有工人都完成后,将计算并打印平均值。

import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;

class Worker implements Runnable {

    private final AtomicInteger sum;
    private final CountDownLatch latch;

    public Worker(AtomicInteger sum, CountDownLatch latch) {
        this.sum = sum;
        this.latch = latch;
    }

    @Override
    public void run() {
        Random random = new Random();

        try {
            // Sleep a random length of time from 5-10s
            Thread.sleep(random.nextInt(5000) + 5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // Compute x
        int x = random.nextInt(500);

        // Add to the shared sum
        System.out.println("Adding " + x + " to sum");
        sum.addAndGet(x);

        // This runnable is finished, so count down
        latch.countDown();
    }
}

class Program {

    public static void main(String[] args) {
        // There will be 39 workers
        final int N = 39;

        // Holds the sum of all results from all workers
        AtomicInteger sum = new AtomicInteger();
        // Tracks how many workers are still working
        CountDownLatch latch = new CountDownLatch(N);

        System.out.println("Starting " + N + " workers");

        for (int i = 0; i < N; i++) {
            // Each worker uses the shared atomic sum and countdown latch.
            Worker worker = new Worker(sum, latch);

            // Start the worker
            new Thread(worker).start();
        }

        try {
            // Important: waits for all workers to finish.
            latch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // Compute the average
        double average = (double) sum.get() / (double) N;

        System.out.println("    Sum: " + sum.get());
        System.out.println("Workers: " + N);
        System.out.println("Average: " + average);
    }

}

The output should be something like this: 输出应该是这样的:

Starting 39 workers
Adding 94 to sum
Adding 86 to sum
Adding 454 to sum
...
...
...
Adding 358 to sum
Adding 134 to sum
Adding 482 to sum
    Sum: 10133
Workers: 39
Average: 259.8205128205128

Edit: Just for fun, here is an example using ExecutorService , Callable , and Future . 编辑:只是为了好玩,这是一个使用ExecutorServiceCallableFuture的示例。

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledThreadPoolExecutor;

class Worker implements Callable<Integer> {

    @Override
    public Integer call() throws Exception {
        Random random = new Random();

        // Sleep a random length of time, from 5-10s
        Thread.sleep(random.nextInt(5000) + 5000);

        // Compute x
        int x = random.nextInt(500);
        System.out.println("Computed " + x);

        return x;
    }

}

public class Program {

    public static void main(String[] args) {
        // Thread pool size
        final int POOL_SIZE = 10;

        // There will be 39 workers
        final int N = 39;

        System.out.println("Starting " + N + " workers");

        // Create the workers
        Collection<Callable<Integer>> workers = new ArrayList<Callable<Integer>>(N);

        for (int i = 0; i < N; i++) {
            workers.add(new Worker());
        }

        // Create the executor service
        ExecutorService executor = new ScheduledThreadPoolExecutor(POOL_SIZE);

        // Execute all the workers, wait for the results
        List<Future<Integer>> results = null;

        try {
            // Executes all tasks and waits for them to finish
            results = executor.invokeAll(workers);
        } catch (InterruptedException e) {
            e.printStackTrace();
            return;
        }

        // Compute the sum from the results
        int sum = 0;

        for (Future<Integer> future : results) {
            try {
                sum += future.get();
            } catch (InterruptedException e) {
                e.printStackTrace(); return;
            } catch (ExecutionException e) {
                e.printStackTrace(); return;
            }
        }

        // Compute the average
        double average = (double) sum / (double) N;

        System.out.println("         Sum: " + sum);
        System.out.println("     Workers: " + N);
        System.out.println("     Average: " + average);
    }

}

The output should look like this: 输出应如下所示:

Starting 39 workers
Computed 419
Computed 36
Computed 338
...
...
...
Computed 261
Computed 354
Computed 112
         Sum: 9526
     Workers: 39
     Average: 244.25641025641025

您可以使自己对java.util.concurrent.Future以及所有相关联的东西(例如ThreadPools,Executors等)广为人知。Teaser: Future是具有返回值的线程。

use a ExecutorService and submit each task (as a Callable ) to it 使用ExecutorService并将每个任务(作为Callable )提交给它

you'll get a Future for each task submitted 您将为提交的每个任务获得未来

List<Future<ResultType>> results = exec.invokeAll(tasks);//tasks is a set of Callable<ResultType>
//invokeAll blocks untill all tasks are finished
for(Future<ResultType> f:results){
    ResultType x=f.get();//loop over Futures to get the result
    //do something with x
}

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

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