如何使用固定数量的工作线程实现简单线程
时间: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(); }