2010-05-29 3 views
3

Переменная класса out в классе MyThread должна быть объявлена ​​изменчивой в этом коде или будет переноситься «изменчивость» переменной stdout в классе ThreadTest?Должна ли эта переменная быть объявлена ​​нестабильной?

import java.io.PrintStream; 

class MyThread implements Runnable 
{ 
    int id; 
    PrintStream out; // should this be declared volatile? 

    MyThread(int id, PrintStream out) { 
     this.id = id; 
     this.out = out; 
    } 

    public void run() { 
     try { 
      Thread.currentThread().sleep((int)(1000 * Math.random())); 
      out.println("Thread " + id); 
     } 
     catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
    } 
} 

public class ThreadTest 
{ 
    static volatile PrintStream stdout = System.out; 

    public static void main(String[] args) { 
     for (int i = 0; i < 10; i++) { 
      new Thread(new MyThread(i, stdout)).start(); 
     } 
    } 
}

ответ

2

Квалификатор volatile не будет переноситься, и он не имеет никакого смысла в вышеуказанном коде. Volatile устанавливает барьер памяти при чтении и записи в переменную, которая никогда не изменяется после инициализации в конструкторе. По этой же причине нестабильный классификатор в ThreadTest не имеет никакой цели.

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

+1

Эммм ... мое чтение модели памяти JLS spec заключается в том, что между созданием (энергонезависимым, не финальным) полем в конструкторе и чтением его в другом потоке не существует отношения «произойдет-до».Таким образом, в примере этот параметр не является избыточным. –

+0

@Stephen C невозможно, чтобы другой поток мог получить доступ к переменной перед возвратом конструктора. –

+1

Нет, если конструктор не произведет «необоснованно опубликованный» объект (не здесь). Но здесь мы говорим о другом потоке, обращающемся к переменной после возврата конструктора; то есть в методе «run». –

0

Это определенно не переносит. Хотя я не уверен, что вы пытаетесь сделать. volatile квалифицирует поле в ThreadTest, а не значение.

2

Должен ли переменная out в классе MyThread объявляться волатильной в этом коде или будет переноситься «изменчивость» переменной stdout в классе ThreadTest?

Волатильность не переносится, потому что вы фактически передаете значение переменной.

По моему чтению JLS memory model спецификации, volatileтребуется, если бы вы читали out без какой-либо промежуточной синхронизации между потоком, который создал объект и потоком, который использует его.

В указанном коде переменная под угрозой - out. Которая является не-частной переменной и может быть доступна/обновлена ​​на все, что имеет доступ к классу . В вашем примере нет кода, который делает это, но вы можете написать другой класс ... или изменить ThreadTest.

Но в этом случае лучше решения будет:

  • Объявить out в final. semantics of final fields означает, что синхронизация не требуется.

  • Объявление out как private. Теперь «случится раньше» между конструкцией потока и вызовом start() гарантирует, что только возможный доступ к out будет видеть правильное значение.

0

не требуется.

Потому что происходит, перед тем между объектов, которые создаются перед вызовом Thread.start и после вызова Thread.start