不执行无限制线程池执行程序中所有线程的原因是什么

时间:2018-06-26 12:25:47

标签: java multithreading threadpool threadpoolexecutor java-threads

我正在使用ExecutorService
ExecutorService executor = Executors.newFixedThreadPool(20000);
我在ThreadSystem.java类中有两个静态成员:

public static Integer count = 0;
public static Integer rejectedCount = 0;

然后在其中添加线程:

for (i = 0; i < 20001; i++) {
    Runnable worker = new MyThread();
    try {
        executor.execute(worker);
    } catch (RejectedExecutionException ex) {
        rejectedCount++;
    }
}
executor.shutdown();
while (!executor.isTerminated()) {
}

在线程内:

@Override
public void run() {
    ThreadSystem.count++;
    try{   
        Thread.sleep(50);       
    }
    catch(InterruptedException ex){
        Logger.getLogger(MyThread.class.getName()).log(Level.SEVERE, ex.getMessage(),ex);
      }
}

我得到的结果表明有些线程没有执行,count变量不等于创建的线程数,尽管引用拒绝线程的rejectedCount是0:

  

数:19488
拒绝数:0

那么还有什么可以保证我所有线程都可以运行的?那是什么原因:计数(可运行线程)不等于添加的线程

1 个答案:

答案 0 :(得分:6)

您的代码是竞争条件的“完美范例”:您对

的访问
 public static Integer count = 0;

未同步,因此多个线程可能同时执行以下行:

 ThreadSystem.count++;

这可能/可能导致写入丢失,因为多个线程可能同时执行与ThreadSystem.count = ThreadSystem.count + 1等效的操作,并且某些线程会读取该操作的旧的尚未更新的数字。

要么使用适当的synchronized防护罩,要么使用AtomicInteger#incrementAndGet()周围的东西作为计数器。

请注意,在这种情况下,您不得count上进行同步,因为Integer是不可变的对象,并且对装箱的基元(int IntegerlongLong,...)基本上是对该变量的赋值。使用AtomicInteger是解决此特定问题的最佳解决方案。

您的rejectedCount也是如此。(不正确,因为它仅由一个线程更新。)