Итак, проблема в том, что вы позволяете каждому потоку делать 1000 приращений, поэтому вам нужно что-то вроде этого:
while (counter.getCount() < 1000) {
counter.add(1);
}
Решение, которое вы предоставили, может дать вам правильный результат, но вы на самом деле увеличиваете счетчик только с 1 потока. Когда вы создаете синхронизированный блок с synchronized(object) { }
, все потоки будут пытаться получить блокировку для этого блока, но только один будет. В вашем решении это означает, что первый поток, который получает блокировку, будет делать все 1000 приращений. Когда поток снимает блокировку и позволяет другим получить ее, работа уже сделана. Поэтому решение, которое фактически распределяет приращения между тремя потоками, не должно синхронизировать весь цикл for.
Если вы запустите предложенный мной цикл while, вы приблизитесь к 1000, но на самом деле оно может быть больше 1000. Не забудьте запустить вашу программу 10 раз или настроить тестовую функцию, которая запускает ее 100 раз. и сообщает обратно. Проблема в том, что с момента считывания counter.getCount()
значение, возможно, уже изменилось другим потоком. Чтобы надежно всегда получить 1000, вы можете обеспечить исключительные права как на чтение, так и на запись на счетчик:
while (true) {
synchronized (counter) {
if (counter.getCount() < 1000) {
counter.add(1);
} else {
break;
}
}
}
Обратите внимание, что приращение на одну переменную, подобное этой, медленное . Вы делаете только 1000, но попробуйте с миллиардом. Фактически, 3-поточная версия занимает (на моем ПК) 1m17s, тогда как простой последовательный цикл занимает ~ 1,2 секунды. Вы можете решить эту проблему, разделив рабочую нагрузку между потоками и позволив им работать на локальном счетчике с исключительными правами, а затем, наконец, добавить результаты.