Java 如何使用固定数量的工作线程实现简单线程

Java 如何使用固定数量的工作线程实现简单线程,java,multithreading,concurrency,Java,Multithreading,Concurrency,我正在寻找实现以下功能的最简单、最直接的方法: 主程序实例化worker 线程来执行任务 一次只能运行n任务 当到达n时,不再有工人 直到计数 正在运行的线程下降到n下面 使用Executor框架;也就是说,我认为这符合你的要求。使用结果ExecutorService有许多不同的方法,具体取决于您是否希望将结果返回到主线程,任务是否完全自包含,是否有一组任务要提前执行,或者任务是否排队以响应某些事件 Collection<YourTask> tasks = new ArrayL

我正在寻找实现以下功能的最简单、最直接的方法:

  • 主程序实例化worker 线程来执行任务
  • 一次只能运行
    n
    任务
  • 当到达
    n
    时,不再有工人 直到计数 正在运行的线程下降到
    n
    下面

使用Executor框架;也就是说,我认为这符合你的要求。使用结果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);
Collection tasks=new ArrayList();
YourTask yt1=新建YourTask();
...
任务。添加(yt1);
...
ExecutorService exec=Executors.newFixedThreadPool(5);
列表结果=exec.invokeAll(任务);
或者,如果您有一个新的异步任务要执行以响应某个事件,您可能只想使用ExecutorService的简单
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();
        } 
    }
}
private static final int MAX_WORKERS=n;
私有列表工作人员=新的ArrayList(最大工作人员);
私有布尔roomLeft(){
同步(工人){
返回(workers.size()
其中Worker是扩展线程的类。当完成该类的工作时,每个工作者将调用该类的removeWorker方法,并将自身作为参数传入

话虽如此,Executor框架看起来好多了


编辑:有人想解释一下为什么这样糟糕,而不是简单地修改它吗?

正如这里的其他人所提到的,你最好的办法是与类建立一个线程池:

然而,如果您想自己动手,这段代码应该会告诉您如何继续。基本上,只需将每个新线程添加到一个线程组中,并确保组中的活动线程不超过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);
    }
}
Task[]tasks=getTasks();//要完成的任务的数组
ThreadGroup=新的ThreadGroup();
int i=0;
while(i0){
如果(group.activeCount()
/*获得一个一次最多运行5个线程的执行器服务:*/
ExecutorService exec=Executors.newFixedThreadPool(5);
/*对于总共要完成的100项任务*/
对于(int i=0;i<100;i++){
/*…执行要作为可运行任务并发运行的任务:*/
exec.execute(新的Runnable(){
公开募捐{
/*在自己的线程中完成要完成的工作*/
System.out.println(“磨合:+Thread.currentThread());
}
});
}
/*告诉执行人,在完成上述100个步骤后,我们将完成:*/
exec.shutdown();
试一试{
/*任务现在同时运行。我们等待所有工作完成,
*超时时间为50秒:*/
布尔b=执行等待终止(50,时间单位秒);
/*如果执行超时,则返回false:*/
System.out.println(“全部完成:+b);
}catch(InterruptedException e){e.printStackTrace();}
  • 如果您的任务队列不是无界的,并且任务可以在更短的时间间隔内完成,则可以按照专家的建议使用
    Executors.newFixedThreadPool(n)

    此解决方案的唯一缺点是任务队列大小没有限制。您无法控制它。任务队列中的大量堆积将降低应用程序的性能,在某些情况下可能会导致内存不足

  • 如果要使用
    ExecutorService
    并启用
    工作窃取
    机制,其中空闲工作线程通过窃取任务队列中的任务来共享繁忙工作线程的工作负载。它将返回ForkJoinPool类型的Executor服务

    公共静态
    执行器服务newWorkStealingPool
    (int并行)

    创建一个线程池,该线程池维护足够多的线程以支持给定的并行级别,并可以使用多个队列来减少争用。并行级别对应于积极参与或可参与任务处理的最大线程数。实际线程数可能会动态增长和收缩。工作线程aling pool不保证提交任务的执行顺序

  • 我更喜欢
    ThreadPoolExecutor
    ,因为API可以灵活地控制许多参数,这些参数控制流任务的执行

    ThreadPoolExecutor(int corePoolSize, 
                           int maximumPoolSize, 
                           long keepAliveTime, 
                           TimeUnit unit, 
                           BlockingQueue<Runnable> workQueue, 
                           ThreadFactory threadFactory,
                           RejectedExecutionHandler handler)
    
    ThreadPoolExecutor(int-corePoolSize,
    int maximumPoolSize,
    长时间,
    时间单位,
    阻塞队列工作队列,
    ThreadFactory ThreadFactory,
    RejectedExecutionHandler(处理程序)
    
  • 在您的情况下,将
    corePoolSize和maximumPoolSize都设置为N
    。在这里,您可以控制任务队列大小,定义自己的自定义线程工厂和拒绝处理程序策略

    查看相关SE问题以动态控制池大小:

    /* 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(); }
    
    ThreadPoolExecutor(int corePoolSize, 
                           int maximumPoolSize, 
                           long keepAliveTime, 
                           TimeUnit unit, 
                           BlockingQueue<Runnable> workQueue, 
                           ThreadFactory threadFactory,
                           RejectedExecutionHandler handler)