我有一个线程池执行器
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个等待线程?
答案 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并发任务不是一个好主意。你有多少个处理器? ;)