1

Я новичок в потоках в Java и, следовательно, сомневаюсь. Я прочитал, что «синхронизированный нестатический блок методов» позволяет только одному потоку вводить блок (для одного экземпляра нестатического блока, конечно). Однако это не работает. Я что-то упускаю? Посмотрите на следующий код.Блок синхронизации

class A extends Thread 
{ 
    public void run() 
    { 
     B.b.add(); 
    } 
} 

class B 
{ 
    static B b=new B(); 
    int i; 
    public synchronized void add() 
    { 
     i++; 
    } 
} 

public class Sample 
{ 
    public static void main(String[] args) 
    { 
     for(int i=0;i<10;i++) 
     { 
      new A().start(); 
     } 
     System.out.println(B.b.i); 
    } 
} 
+0

wait, это как-то связано с политикой записи кеша? Потому что я ожидал, что результат «10» будет напечатан, но результат случайный, от 0 до 9. – Balu

+1

Извините, он получил его. Основной поток - это печать значения до того, как значение будет увеличено на все потоки (поскольку выполняется параллельно). Как напечатать значение после того, как все потоки завершили выполнение? – Balu

+0

Если вы хотите дождаться всех потоков, к которым вы должны присоединиться после цикла, см .: http://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#join() – rafalopez79

ответ

2

Одна из проблем заключается в том, что ваш основной поток не ждет завершения других потоков, прежде чем он попытается получить результат. Использование 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()); 
    } 
} 
Смежные вопросы