Одна из проблем заключается в том, что ваш основной поток не ждет завершения других потоков, прежде чем он попытается получить результат. Использование Thread # join работает, если вы хотите подождать один поток, но здесь мы хотим дождаться всего 10. Изменение программы для использования CountDownLatch делает основной поток до тех пор, пока все созданные им потоки не будут завершены.
Другая проблема заключается в том, что обновленное значение i не гарантируется быть видимым. Реализации JVM различаются тем, насколько агрессивно они выполняют оптимизацию (например, задержка обновления кешированных значений или переупорядочение байт-кода), которые могут сделать изменения, которые я не вижу в основном потоке. Добавление синхронизированного метода в тот же замок, что и метод add для извлечения значения i, устраняет проблему видимости.
import java.util.concurrent.CountDownLatch;
class A extends Thread {
private CountDownLatch latch;
public A(CountDownLatch latch) {
this.latch = latch;
}
@Override public void run() {
B.b.add();
latch.countDown();
}
}
class B {
static B b=new B();
int i;
public synchronized void add() {
i++;
}
public synchronized int getI() {
return i;
}
}
public class Sample {
public static void main(String[] args) throws Exception {
CountDownLatch latch = new CountDownLatch(10);
for(int i=0;i<10;i++) {
new A(latch).start();
}
latch.await();
System.out.println(B.b.getI());
}
}
wait, это как-то связано с политикой записи кеша? Потому что я ожидал, что результат «10» будет напечатан, но результат случайный, от 0 до 9. – Balu
Извините, он получил его. Основной поток - это печать значения до того, как значение будет увеличено на все потоки (поскольку выполняется параллельно). Как напечатать значение после того, как все потоки завершили выполнение? – Balu
Если вы хотите дождаться всех потоков, к которым вы должны присоединиться после цикла, см .: http://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#join() – rafalopez79