0

Предположим, у меня есть два потока, обновляющих объект, и один поток, читаемый с этого объекта без синхронизации. Очевидно, что это условие запуска. Тем не менее, мне интересно, может ли сама переменная быть только частично написана.Являются ли переменные java сами потоками безопасными? При обновлении переменных?

public class CommonObject extends Object 
{ 
    static int memberVar=-1; 
} 

public class Input1Thread extends Thread 
{ 
    public void run() 
    { 
     while(true) 
      CommonObject.memberVar = 1 
    } 
} 

public class Input2Thread extends Thread 
{ 
    public void run() 
    { 
     while(true) 
      CommonObject.memberVar = 2; 
    } 
} 

public class OutputThread extends Thread 
{ 
    public void run() 
    { 
     while(true) 
      System.out.println("CommonObject.memberVar"+ CommonObject.memberVar); 
    } 
} 

Я бы предположил, значение распечатывается также будет либо 2 или 1. Тем не менее, мне было интересно, если это было возможно, что переменная может быть установлена ​​на полпути?

В качестве примера я использовал примитивы, но я бы хотел, чтобы ответ также касался объектов, если он отличается.

+0

Я думаю, что этот вопрос и ответ лучше. Также они более специфичны для разрыва слова. –

ответ

3

Это зависит от типа переменной.

double s и long s (два 64-битные типов в Java) разрешаются словесной слеза, если они не volatile, в то время как все другие виды (в том числе ссылки) никогда не могут слезы. Разрывание слов даст вам поведение, о котором вы беспокоитесь: некоторые из байтов относятся к старому значению, некоторые из них относятся к новому значению, а общий результат - значение, которое не является ни старым, ни новым.

Это указано в JLS 17.7:

Для целей модели памяти языка программирования Java, один записи в энергонезависимую длинной или двойной значение обрабатывается как два отдельных записей: один для каждого 32 -битной половины. Это может привести к ситуации, когда поток видит первые 32 бита 64-битного значения из одной записи, а второй 32 бита из другой записи.

Запись и чтение изменчивых длинных и двойных значений всегда являются атомарными.

Запись и чтение ссылок всегда являются атомарными, независимо от того, реализованы ли они как 32-разрядные или 64-битные значения.

Конечно, введение гонок данных представляет собой целый ряд проблем; но ваш вопрос был специально нацелен на разрывание слов, поэтому я только обращаюсь к этому здесь, за исключением того, что «только потому, что вы можете, не означает, что вам следует». Вы должны быть осторожны, чтобы проанализировать каждую гонку данных, и доказать, что она является доброкачественной (поскольку некоторые из них - как кеширование String.hashCode ее значений).

+0

Отличный ответ. Я думаю, что этот ответ лучше ответа в другом вопросе. –

+0

Итак, долгое время полностью безопасно, если оно неустойчиво? –

+0

@GC_ Это зависит от того, что вы подразумеваете под «безопасным»! Это не будет словесным ...но в гонках данных есть другие проблемы, такие как появление не по порядку или, возможно, не видение других потоков вообще (если они кэшируются в локальном регистре). – yshavit

-1

Это безопасно для примитивов, но не безопасно для Objects.for например, объект А имеет две переменные INT A, B, если вы пытаетесь изменить их значения в двух разных потоков, вы увидите, что значения из оба потока могут появляться одновременно.

+0

Объекты не являются переменными. Вопрос касался только переменных. Кроме того, это небезопасно для _all_ примитивных типов. JLS явно позволяет обновлять «двойные» переменные и «длинные» переменные неатомными. (См. Ответ yshavit) –

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