LinkedBlockingQueue无法等待线程执行

时间:2014-12-18 19:00:10

标签: java multithreading

我正在创建一个WordCounter,它有几个线程计算不同文件中的单词。除了一个小问题,我已经完成了一切工作。

我无法找出等待线程完成的正确方法。如果我设置Thread.sleep等待很短的时间,一切都有效,唯一的问题是,如果计数器花费的时间比睡眠时间长,这将不是一个合适的解决方案。

import java.io.*;
import java.util.*;
import java.util.concurrent.BlockingQueue;

public class WordCounter implements Runnable{
    private String file;
    private BlockingQueue<Integer> q;
    private int words = 0;

    public WordCounter(String f, BlockingQueue<Integer> queue){
        file = f;
        q = queue;
    }

    public void run(){
        try{
            Scanner in = new Scanner(new File(file));

            while (in.hasNext()){
                in.next();
                words++;
            }
            in.close();
            System.out.println(file + ": " + words);
            q.add(words);
        }

        catch (FileNotFoundException e){
            System.out.println(file + " blev ikke fundet.");
        }
    }

}

这是来自实际字计数器的代码。我希望我的主线程等待这些字计数器线程执行q.add(单词);在做其他任何事情之前发挥作用。

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

public class MainThread implements Runnable{

    private String[] arguments;

    public MainThread(String[] args){
        arguments = args;
    }

    public void run() {

        final BlockingQueue<Integer> queue = new LinkedBlockingQueue<Integer>();

        for(String f : arguments){
            WordCounter c = new WordCounter(f, queue);
            Thread t = new Thread(c);
            t.start();  
        }
        while(!queue.isEmpty()){
            try {
                System.out.println(queue.take());
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

这是主线程。在我继续在底部的while语句之前,我需要某种方式等待其他线程完成,但是如何?

提前致谢。

4 个答案:

答案 0 :(得分:1)

使用ExecutorService并等待Future返回。下面的代码将每个任务提交给执行程序服务(线程池)中的一个线程,并返回该任务的未来。当所有提交它将等待未来。 get方法仅在run方法在任务中完成时返回。

public class MainThread implements Runnable{

    private String[] arguments;

    public MainThread(String[] args){
        arguments = args;
    }

    public void run() {

        ExecutorService e = Executors.newFixedThreadPool(arguments.length);
        final BlockingQueue<Integer> queue = new LinkedBlockingQueue<Integer>();
        List<Future<?>> tasks = new ArrayList<>();
        for(String f : arguments){
            tasks.add(e.submit(new WordCounter(f, queue)));
        }
        for(Future<?> f : tasks) {
            f.get();
        }
        while(!queue.isEmpty()){
            try {
                System.out.println(queue.take());
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

然而

您可以完全删除BlockingQueue并让每个任务都为Callable<Integer>,只需返回words变量即可使代码更清晰。当你致电future.get()返回值时,会有单词count。

答案 1 :(得分:0)

这就是我要做的事情:

  1. 创建一个计数器变量(以下是如何以对multi-threads安全的方式执行)以跟踪您在主要产生的线程数量 线程
  2. 创建一个带有函数签名的接口 递增/递减计数器
  3. 在你的网站中实现该接口 主线
  4. 将工作线程子类化为接受该接口 参数
  5. 一旦工作线程完成,调用该接口 减少运行线程的数量。
  6. 在主线程上执行递减函数,添加一个 一旦计数器为0,就要做一些事情。

答案 2 :(得分:0)

您需要将创建的线程保留在列表中,并从当前线程中加入它们。 像这样:

List<Thread> threads = new LinkedList<Thread>();

for (String f : arguments) {
  WordCounter c = new WordCounter(f, queue);
  Thread t = new Thread(c);
  t.start();
  threads.add(t);
}

for (Thread t : threads) {
  t.join();
}

join()方法将一直阻塞,直到线程终止。

答案 3 :(得分:0)

如果您知道要等待多少线程,则可以使用共享semaphore。工作线程在信号量完成后每次调用release;主线程调用acquire(n),其中n是工作线程的数量,这导致主线程等到n允许可用(即直到所有n工作线程为止完成)。