2016-03-24 4 views
1

В соответствии с некоторыми документами, которые я прочитал в Интернете, переменные класса Atomic, такие как AtomicInteger, AtomicLong, ... разрешают только один поток для доступа к ним в одно и то же время. Но когда я попробовал тестирование с AtomicBoolean, что-то пошло не так. НапримерДействительно ли AtomicBoolean гарантирует «безопасную нить»?

public class TestAtomicBoolean { 
    public static void main(String[] args) { 
     final AtomicBoolean atomicBoolean = new AtomicBoolean(false); 

     new Thread("T1") { 
      @Override 
      public void run() { 
       while (true) { 
        System.out.println(Thread.currentThread().getName() + " is waiting for T3 set Atomic to true. Current is " + atomicBoolean.get()); 
        if (atomicBoolean.compareAndSet(true, false)) {       
         System.out.println("Done. Atomic now is " + atomicBoolean.get()); 
         break; 
        }      
       } 
      } 
     }.start(); 

     new Thread("T2") { 
      @Override 
      public void run() { 
       while(true) { 
        System.out.println(Thread.currentThread().getName() + " " + atomicBoolean.get());      
       }    
      }   
     }.start(); 

     new Thread("T3") { 
      @Override 
      public void run() { 
       System.out.println(Thread.currentThread().getName() + " " + atomicBoolean.get()); 
       System.out.println(Thread.currentThread().getName() + " is setting atomic to true"); 
       atomicBoolean.set(true); 
       System.out.println(Thread.currentThread().getName() + " " + atomicBoolean.get()); 
      }   
     }.start();     
    } 
} 

Выходной

T1 is waiting for T3 set Atomic to true. Current is false 
T1 is waiting for T3 set Atomic to true. Current is false 
T3 is setting atomic to true 
T2 false 
T3 true (*) 
T1 is waiting for T3 set Atomic to true. Current is false (*) 
T2 true 
Done. Atomic now is false 
T2 false 

В 2 линии (*), хотя Т3 установить AtomicBoolean истинно, после этого, Т1 прочитать значение было ложным. Итак, T1 и T3 одновременно получают доступ к AtomicBoolean? Я не могу понять, как работает AtomicBoolean.

Может кто-нибудь мне помочь?

+0

@ElliottFrisch Не могли бы вы объяснить более четко? :( –

+0

Нет никакой волшебной пули, которая обеспечит безопасность потока. Даже если каждая операция, выполняемая вашим кодом, индивидуально поточно-безопасна, это не обязательно сделает все это потокобезопасным. –

ответ

2

AtomicBoolean определенно атомный и потокобезопасный.

Но в вашем примере вы пытаетесь проверить эту атомную природу AtomicBoolean, полагаясь на порядок: System.out.println печатает журналы, которые вводят в заблуждение.

Так что, если мы посмотрим на System.out.println() код:

public void println(String x) { 
    synchronized (this) { 
     print(x); 
     newLine(); 
    } 
} 

Мы видим поток событий с выше println() метода в контексте.

Короткий ответ

Thread T1 печатает -> ждет T3 установить Atomic истина. Ток ложный
Резьба T1 печатает -> ждет, когда T3 установлен Atomic в true. Ток ложный
Резьба T3 -> T3 устанавливает атомную истину
Резьба T1 вызывает sysout для печати -> ожидает, что T3 установлен Atomic в true. Ток ложен (Позвонил метод SYSOUT но замокло еще не приобрело)
Thread T3 принтов -> печать Т3 истинных
T1 Thread SYSOUT полные и отпечатки -> ждет T3 установить Atomic истину. Current is false

Порядок журналов создает впечатление, что T1 не прочитал текущее значение atomicBoolean, тогда как это связано с чередованием потоков, которые могут произойти при выполнении System.out.println.

Подробная последовательность

Применение начинается с начального значения false для atomicBoolean

final AtomicBoolean atomicBoolean = new AtomicBoolean(false); 

первых двух бревен с вашего выхода взяты из T1, как ожидалось, и он выводит значение atomicBoolean как false. Пока мы будем игнорировать T2, чтобы упростить, поскольку мы можем видеть поток даже с двумя потоками.

Теперь T3 начинает выполнение и собирается сделать atomicBoolean до true, как указано в выводе.

T3 is setting atomic to true 

И сразу после печати вышеуказанной строки T1 получает шанс выполнить. В этот момент значение atomicBoolean составляет false. Поэтому JVM создает строку T1 is waiting for T3 set Atomic to true. Current is false и о вызове или только что ввела метод System.out.println, но еще не достигла инструкции synchronized(this), и поэтому на замок еще не получен.

На данный момент это может случиться Т3 имеет свою очередь, чтобы продолжить выполнение и делает atomicBoolean к true, а также выводит строку T3 true с помощью System.out.println() т.е. получает и освобождает замок (на this).

Теперь T1 возобновляет выполнение с того места, где он находился в последний раз, то есть System.out.println. Но помните, что значение String, которое он пытается распечатать, уже было построено, и его значение равно T1 is waiting for T3 set Atomic to true. Current is false. Итак, теперь T1 печатает эту строку и продолжает.

Эффективно с этим потоком журналы будут такими, какие вы наблюдали.

T3 true 
T1 is waiting for T3 set Atomic to true. Current is false 

наглядного представления

Ниже поток w.r.t T1 & T3 и (пытается) фиксирует сказанное выше. указывает, что в данный момент выполняется поток. Пробелы указывают, что он ждет своего поворота.

1(false) 1(false)   1(false)just invoked 1(false)completed 
T1 -------------------   ------    ------------------ 
T3     ----------  ---------------- 
         2(false)  3(true) 

LEGEND: 
1(false) - printing of T1 is waiting for T3 set Atomic to true. Current is false 
2(false) - printing of T3 is setting atomic to true 
3(true) - printing of T3 true 
+0

Использовать структуру ведения журнала log4j для многопоточности http://logging.apache.org/log4j/2.x/ – mubeen

+0

@mubeen Откровенно говоря, не уверен, что если такой журнал уже существует или может быть достигнут в нашем коде. Один из вариантов, о котором я могу думать, - это написать полезный класс и метод 'static synchronized', который внутренне вызывает' sysout() '. Но я чувствую и почти вижу, что еще есть небольшое окно, в котором может произойти вышеуказанный поток. –

+0

Я получил его. –

0

Вместо того, чтобы ссылаться на «какие-то документы», вы можете попробовать читать официальные документы на https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/package-summary.html

быстрый и простой способ думать о классах в атомном пакете является то, что каждый метод, такой как получить, set, compareAndSet ведет себя так, как если бы он был синхронизирован (забыв ленивые и слабые методы).

+0

Я прочитал это официальные документы, но я все еще не понимают :(«AtomicBoolean: логическое значение, которое может быть обновлено атомарно». В моем примере это не «атомный»: s 2 потока могут обращаться к нему в одно и то же время: s –

Смежные вопросы