如何懒惰地创建供Java线程池使用的任务

时间:2012-03-06 20:02:28

标签: java multithreading lazy-loading threadpool java.util.concurrent

我正在用Java编写一个负载测试应用程序,并且有一个线程池可以对正在测试的服务器执行任务。所以要创建1000个作业并在5个线程中运行它我会做这样的事情:

    ExecutorService pool = Executors.newFixedThreadPool(5);
    List<Runnable> jobs = makeJobs(1000);
    for(Runnable job : jobs){
        pool.execute(job);
    }

但是我不认为这种方法可以很好地扩展,因为我必须提前制作所有“工作”对象并让它们在内存中存放直到需要它们为止。

我正在寻找一种方法让池中的线程在每次需要新工作时进入某种“JobFactory”类,并且工厂根据请求构建Runnables,直到所需的工作数量为止已经运行了。工厂可能会开始返回'null',向线程发出信号,表示没有更多的工作要做。

我可以手动编写这样的代码,但它似乎是一个常见的用例,并且想知道在我可以使用的奇妙但复杂的“java.util.concurrent”包中是否有任何东西?< / p>

2 个答案:

答案 0 :(得分:5)

您可以使用AtomicInteger在线程池的执行线程中完成所有工作,以监控已执行的可运行数量

 int numberOfParties = 5;
 AtomicInteger numberOfJobsToExecute = new AtomicInteger(1000);
 ExecutorService pool = Executors.newFixedThreadPool(numberOfParties );
 for(int i =0; i < numberOfParties; i++){
     pool.submit(new Runnable(){
        public void run(){
            while(numberOfJobsToExecute.decrementAndGet() >= 0){
                makeJobs(1).get(0).run();
            }
        }
     });
 }

您还可以将返回的Future存储在List中,并将get()存储在它们上以等待完成(以及其他机制)

答案 1 :(得分:4)

槽糕。您可以创建具有固定容量的BlockingQueue<Runnable>,并让每个工作线程将Runnable出列并运行它。然后你可以有一个生产者线程,这就是将作业放入队列的原因。

主线程会做类似的事情:

// 100 is the capacity of the queue before blocking
BlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>(100);
// start the submitter thread
new Thread(new JobSubmitterThread(queue)).start();
// make in a loop or something?
new Thread(new WorkerThread(queue)).start();
new Thread(new WorkerThread(queue)).start();
...

工人看起来像是:

public class WorkerThread implements Runnable {
     private final BlockingQueue<Runnable> queue;
     public WorkerThread(BlockingQueue<Runnable> queue) {
         this.queue = queue;
     }
     public void run() {
         // run until the main thread shuts it down using volatile boolean or ...
         while (!shutdown) {
             Runnable job = queue.take();
             job.run();
         }
     }
}

作业提交者看起来像是:

 public class JobSubmitterThread implements Runnable {
     private final BlockingQueue<Runnable> queue;
     public WorkerThread(BlockingQueue<Runnable> queue) {
         this.queue = queue;
     }
     public void run() {
         for (int jobC = 0; jobC < 1000; jobC++) {
             Runnable job = makeJob();
             // this would block when the queue reaches capacity
             queue.put(job);
         }
     }
 }