ThreadPoolExecutor只运行第一个runnable

时间:2015-05-27 12:16:36

标签: java multithreading executorservice

我有一个线程池执行器

private ExecutorService exec=Executors.newCachedThreadPool();

我有一个班级

class MyCallable implements Callable<String>{

    private ReentrantLock lock=new ReentrantLock();

    private Condition cond=lock.newCondition();


    public String call(){

    System.out.println("TEST!!);
    try{
      lock.lock();
      cond.await();
    }finally{
       lock.unlock();
    }
   }
}

我做了:

for(int i=0;i<10000;i++){
   exec.submit(new MyCallable());
}

我希望拥有10000个等待callables的线程,但我只能看到一个测试!!在我的日志中,所以它只提交我的任务一次,为什么它会冻结?我的callable在每个对象实例中都有自己的锁,如何拥有1000个等待线程?

3 个答案:

答案 0 :(得分:1)

我拿了你的代码,填写了缺失的部分,修复了编译错误并运行它。它打印“TEST !!”很多次。如果我将任务数量减少到合理的数量,它将运行完成。如果我把它保留在10,000,则测试失败,OOME说它不能再分配任何线程堆栈。

  

我想拥有10000个等待callables的线程

我的测试表明,许多线程会导致内存不足。这真的,不是一个好主意。

以下是我使用的确切代码:

package test;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ExecutorTest {

    public static void main(String[] args) {
        ExecutorService exec = Executors.newCachedThreadPool();
        for (int i = 0; i < 10000; i++) {
            exec.submit(new MyCallable());
        }
    }
}


package test;

import java.util.concurrent.Callable;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

class MyCallable implements Callable<String> {

    private ReentrantLock lock = new ReentrantLock();

    private Condition cond = lock.newCondition();

    public String call() {

        System.out.println("TEST!!");
        try {
            lock.lock();
            cond.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
        return "foo";
    }
}

这是while(true) {await}测试:

[steve@newbox ~]$ cat ./workspace/test/src/test/CondAwait.java 
package test;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class CondAwait {

    public static void main(String[] args) throws InterruptedException {
         ReentrantLock lock = new ReentrantLock();

         Condition cond = lock.newCondition();
         lock.lock();
         while(true){
             System.out.println("Hi!");
             cond.await();
         }
    }

}
[steve@newbox ~]$ java -cp ./workspace/test/bin test.CondAwait 
Hi!
^C[steve@newbox ~]$ 

简而言之,主线程在第一次await调用中冻结......正如我所期望的那样。

  

我同意这不是一个好主意,但那些线程会像请求缓存一样,用户发送请求,它的处理器应该放入线程池,如果我们每秒有10k个请求,你会看到池中有10k个线程。请建议如何做得更好。

使用有界线程池,并将绑定设置为大致等于您拥有的核心数。

当然,你不会同时暂停你的10,000个callables,但这是一件好事。

如果这些可调用对象是为了模拟外部响应事件等待几秒钟的请求,那么最多100个线程池可能是合理的。但是如果你真的需要大规模的并行性,那么你应该看一下使用NIO选择器的东西,这样少量的工作线程可以运行大量的请求,交错它们而不是阻塞I / O.

答案 1 :(得分:0)

查看班级java.util.concurrent.CyclicBarrier。正如其JavaDoc中所述,它是:

  

允许一组线程等待的同步辅助   彼此达成共同的障碍点。

每个线程都需要调用屏障的方法await。这意味着线程被暂停,直到Barrier达到了预期的线程数或发生了超时。

答案 2 :(得分:0)

我刚试过你的程序,它对我来说很好。我可以看到多个任务在运行。

public class MyCallable implements Callable<String> {

    private ReentrantLock lock = new ReentrantLock();
    private Condition cond = lock.newCondition();

    public String call() {
        System.out.println("TEST!!");
        try {
           lock.lock();
           cond.await();
        } catch (InterruptedException e) {
           e.printStackTrace();
        } finally {
           lock.unlock();
        }
        return "done";
    }

    public static void main(String[] args) {
        ExecutorService service = Executors.newCachedThreadPool();
        for (int i = 0; i < 10; i++) {
           service.submit(new MyCallable());
        }
    }
}

我建议10000并发任务不是一个好主意。你有多少个处理器? ;)