如何使用固定数量的工作线程实现简单线程
时间:2020-03-06 14:38:29 来源:igfitidea点击:
我正在寻找实现以下目标的最简单,最直接的方法:
- 主程序实例化工作线程来执行任务。
- 一次只能运行n个任务。
- 当达到
n时,直到正在运行的线程数降到n以下为止,不再启动任何工作程序。
解决方案
使用执行器框架;即newFixedThreadPool(N)
我认为Executors.newFixedThreadPool符合要求。有多种不同的方法可以使用生成的ExecutorService,具体取决于我们是希望将结果返回到主线程,还是该任务完全独立,以及是否有要执行的任务集合,或者是否响应某些事件将任务排入队列。
Collection<YourTask> tasks = new ArrayList<YourTask>(); YourTask yt1 = new YourTask(); ... tasks.add(yt1); ... ExecutorService exec = Executors.newFixedThreadPool(5); List<Future<YourResultType>> results = exec.invokeAll(tasks);
另外,如果我们有一个新的异步任务要执行以响应某个事件,则可能只想使用ExecutorService的简单execute(Runnable)方法。
Executors.newFixedThreadPool(int)
Executor executor = Executors.newFixedThreadPool(n);
Runnable runnable = new Runnable() {
public void run() {
// do your thing here
}
}
executor.execute(runnable);
如果要自己滚动:
private static final int MAX_WORKERS = n;
private List<Worker> workers = new ArrayList<Worker>(MAX_WORKERS);
private boolean roomLeft() {
synchronized (workers) {
return (workers.size() < MAX_WORKERS);
}
}
private void addWorker() {
synchronized (workers) {
workers.add(new Worker(this));
}
}
public void removeWorker(Worker worker) {
synchronized (workers) {
workers.remove(worker);
}
}
public Example() {
while (true) {
if (roomLeft()) {
addWorker();
}
}
}
其中Worker是我们扩展Thread的类。完成工作后,每个工作人员都会调用此类的removeWorker方法,并将自身作为参数传递。
话虽如此,Executor框架看起来要好得多。
编辑:有人在乎解释为什么这是如此糟糕,而不是仅仅修改它吗?
正如这里的其他人所提到的,最好的选择是使用Executors类创建线程池:
但是,如果我们想自己动手,此代码应为我们提供一个进行下一步的思路。基本上,只需将每个新线程添加到线程组中,并确保该组中活动线程的数目永远不超过N:
Task[] tasks = getTasks(); // array of tasks to complete
ThreadGroup group = new ThreadGroup();
int i=0;
while( i<tasks.length || group.activeCount()>0 ) {
if( group.activeCount()<N && i<tasks.length ) {
new TaskThread(group, tasks[i]).start();
i++;
} else {
Thread.sleep(100);
}
}
/* Get an executor service that will run a maximum of 5 threads at a time: */
ExecutorService exec = Executors.newFixedThreadPool(5);
/* For all the 100 tasks to be done altogether... */
for (int i = 0; i < 100; i++) {
/* ...execute the task to run concurrently as a runnable: */
exec.execute(new Runnable() {
public void run() {
/* do the work to be done in its own thread */
System.out.println("Running in: " + Thread.currentThread());
}
});
}
/* Tell the executor that after these 100 steps above, we will be done: */
exec.shutdown();
try {
/* The tasks are now running concurrently. We wait until all work is done,
* with a timeout of 50 seconds: */
boolean b = exec.awaitTermination(50, TimeUnit.SECONDS);
/* If the execution timed out, false is returned: */
System.out.println("All done: " + b);
} catch (InterruptedException e) { e.printStackTrace(); }

