我正在创建一个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语句之前,我需要某种方式等待其他线程完成,但是如何?
提前致谢。
答案 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)
这就是我要做的事情:
答案 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
工作线程为止完成)。