В чем причина не выполнения всех потоков в неограниченном пуле потоков? - PullRequest
0 голосов
/ 26 июня 2018

Я использую 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 голосов
/ 26 июня 2018

Ваш код является «идеальным примером» состояния гонки: ваш доступ к

 public static Integer count = 0;

не синхронизирован, поэтому несколько потоков могут выполнять эту строку одновременно:

 ThreadSystem.count++;

Это может / может привести к потере записи, поскольку несколько потоков могут одновременно делать эквивалент ThreadSystem.count = ThreadSystem.count + 1, а некоторые будут читать старый и еще не обновленный номер для операции.

Либо используйте соответствующие synchronized охранники, либо используйте что-нибудь вместе AtomicInteger#incrementAndGet() для счетчика.

Обратите внимание, что в этом случае нельзя синхронизировать с count, поскольку Integer является неизменным объектом и выполняет операции с примитивами в штучной упаковке (от int до Integer, long Long, ...) в основном присваивания переменной. Использование AtomicInteger является лучшим решением для данной проблемы.

То же самое верно для вашего rejectedCount. (Не соответствует действительности, поскольку это обновляется только одним потоком.)

...