当我尝试学习Java线程时,我通常在同一个类中遇到wait()
和notify()
的代码示例(事实上几乎所有这些都是生产者 - 消费者示例)。在谷歌搜索各种例子后,遗憾的是我无法找到我需要的案例:
我想到了一种类似的方法(让n为5):
List<Runnable> runnables = new ArrayList<Runnable>();
for(int i = 0 ; i < 5 ; i++){
runnables.add(new MyWorker(params));
}
for(Runnable myWorker : runnables){
myWorker.run();
}
由于wait()
不支持多个对象,所以我不能继续这样做。另一个解决方案是在管理器线程上实现忙等待,该线程为每个worker调用一些isFinished标志。但我不确定这是一个好方法(据我所知这是资源浪费)
答案 0 :(得分:3)
在执行者框架的形式中,Java 6及更高版本中有一个现成的工具。
由于您希望拥有固定的线程池,因此最好使用:
ExecutorService service = Executors.newFixedThreadPool(5);
然后,您可以使用Runnable
方法(由.execute()
界面定义)提交Executor
个实例。一旦池中的线程可用,它们将被提交到工作队列并出列。
如果您的各个线程工作方法返回一个值(即它们实现Callable<Something>
),那么您可以使用.submit()
方法(由ExecutorService
定义,也是一个扩展的接口Executor
),它将返回Future<Something>
,您将.get()
计算出的值。
以各种方式终止线程池:.shutdown()
是最基本的,并将同步等待仍然活动的线程终止(并阻止提交新作业)。
Javadocs:Executors,ExecutorService,ThreadPoolExecutor。
其他链接:a book you should buy for all things thread-related(不包括Java 7的ForkJoinPool
)。
PS:多么幸运,sample chapter of the book above (PDF)涵盖任务执行;)
答案 1 :(得分:1)
您可以使用semaphore
和wait/notify
方法来完成您要执行的操作。方法是:
semaphore
。 queue
中的任务可用。semaphore
。semaphore
。将所有四个步骤永远放在循环中,您就可以使用任务执行器了。这仅用于学习目的,因为@fge表示已存在ThreadPoolExecuter
,它可以为您做同样的事情并且更加优化。
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.Semaphore;
public class ThreadExecuter extends Thread {
Queue<Runnable> tasks = new LinkedList<Runnable>();
Semaphore s;
Object bin = new Object();
public ThreadExecuter(int n) {
s = new Semaphore(n);
}
public void addTask(Runnable r) {
synchronized (bin) {
tasks.add(r);
bin.notifyAll();
}
}
public void run() {
while (true) {
try {
final Runnable r;
synchronized (bin) {
while (tasks.isEmpty())
bin.wait();
r = tasks.poll();
}
s.acquire();
new Thread() {
public void run() {
r.run();
s.release();
}
}.start();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
主要方法如下:
import java.util.Random;
public class ThreadTest {
/**
* @param args
*/
public static void main(String[] args) {
/* to make maximum 10 threads each running 1 runnable */
ThreadExecuter executer = new ThreadExecuter(10);
executer.start();
for(int i = 0; i < 5000; i++) {
/* add task in executer, this is non blocking */
executer.addTask(new Runnable() {
@Override
public void run() {
System.out.println("Task Executed in "
+ Thread.currentThread().getId());
try {
Thread.sleep(new Random().nextInt(8000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}
}