2010-08-14 2 views
3

Это может быть глупый вопрос, но может ли выход этой программы (как она есть) равняться нулю?Выход программы на Java - параллельный

public class Test2{ 

    int a = 0; 
    AtomicInteger b = new AtomicInteger(); 
    public static Test2 c = new Test2(); 

    public static void main(String[] args){ 

     Thread t1 = new Thread(new MyTest1()); 
     Thread t2 = new Thread (new Mytest2()); 

     t1.start(); 
     t2.start(); 
    } 

} 

class MyTest1 implements Runnable{ 

    public void run(){ 
     Test2.c.a = 1; 
     Test2.c.b.compareAndSet(0,1); 

    } 
} 

class Mytest2 implements Runnable{ 
    public void run(){ 
     int x = 0; 

     if(Test2.c.b.get() == 1) 
      x = Test2.c.a; 

     System.out.println("Value of x = "+x); 
    } 

} 

Причина Я спрашиваю это, хотя я использую AtomicInteger, заявление, если() в MyTest2 может быть выполнена первой, а затем х будет иметь значение zero..right?

или я не думаю, что прямо.

Любая помощь будет высоко оценена.

ответ

5

Может ли выход этой программы (как она есть) равняться нулю?

Да, это возможно. Код не гарантирует, что t1 закончит до того, как закончится t2. Если это ваше намерение, вы можете найти CountdownLatch или CyclicBarrier. Нажмите ссылки, их javadocs содержит примеры кода.


То есть, я бы предпочел передать ссылку из AtomicInteger в качестве аргумента конструктора из обоих runnables вместо доступа к нему статический путь.

+0

Спасибо ... Я понимаю ... Я только что увидел фрагмент кода, и комментарии читают «output будет 1» - и, следовательно, причина, по которой я разместил его здесь. – Achilles

+0

Вещь, которая меня беспокоит, заключается в том, что если вы сохраняете вышеуказанные утверждения в таком порядке: t1.start(); t2.start(); Тогда выход всегда 1, но если вы отмените заказ на: t2.start(); t1.start(); Тогда выход всегда равен 0. Что действительно странно, даже после 100 прогонов, я не могу заставить его производить разные выходные данные для одного и того же заказа. – Achilles

+2

Возможно, у вас есть один основной процессор. На моей двухъядерной машине я вижу «0» примерно каждые 5 запусков. В любом случае код, размещенный как далеко, не гарантирует синхронизацию потоков каким-либо образом. Нити приводят к их собственной жизни без какой-либо помощи по синхронизации. Для другого примера кода, использующего 'CyclicBarrier', вы можете найти [этот ответ] (http://stackoverflow.com/questions/3379797/java-threaded-serial-port-read-with-java-util-concurrent-thread-access/ 3380175 # 3380175). – BalusC

1

С одним небольшим изменением вы можете гарантии, что выход будет 1:

public void run(){ 
    int x = 1; 

    if(Test2.c.b.get() == 1) 
     x = Test2.c.a; 

    System.out.println("Value of x = "+x); 
} 

Из-за упорядочения гарантий летучего чтения/записи:

  • x является Initally 1
  • Единственным другим значением, которое может быть присвоено x, является значение Test2.c.a
  • Test2.c.a могут быть скопированы x только если 1 был ранее прочитанных из Test2.c.b
  • 1 записывается Test2.c.b только после написания 1 к Test2.c.a
  • Поскольку Test2.c.b летуч, любой поток, который читает также соблюдает все предыдущие операции записи ко всем переменным (изменчивым или нет) тем же потоком, который написал в Test2.c.b. Это означает, что t2 также видит запись в 1 к Test2.c.a
  • Если тест не пройден (то есть чтение из Test2.c.b возвращает нечто иное, чем 1), то х сохраняет свое первоначальное значение 1, поэтому выход все еще 1.

Я подозреваю, что это то, что автор этой программы пытается показать, и значение по умолчанию для 0x была опечатка.

+0

Хорошее объяснение, но ИМО оригинал автора просто сделал ошибку мышления, а изменение возвращаемого значения по умолчанию не является решением, а обходным путем. Тогда зачем использовать потоки для этой цели? – BalusC

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