Создал класс
SomeThread implements Runnable
В нем один метод incrementString();
добавляющий букву к строке и выводящий строки на консоль. Метод вызывается через run();
Если incrementString();
пометить synchronized, то вывод стабильно такой:
a-b Thread-1
aa-bb Thread-0
А если без synchronized (как в коде ниже), то выводит, кроме прочих вариантов и так:
a-b Thread-1
a-b Thread-0
Не могу понять почему так происходит. Получается, что одна из нитей не выполняет операцию s1 +=
или s2 +=
Кто поможет разобраться в этом конкретном примере? Заранее спасибо)
public class TestThread
{
public static void main(String[] args)
{
SomeThread someThread = new SomeThread();
Thread thread1 = new Thread(someThread);
Thread thread2 = new Thread(someThread);
thread1.start();
thread2.start();
}
}
class SomeThread implements Runnable
{
String s1 = "";
String s2 = "";
@Override
public void run()
{
try
{
incrementString();
}
catch (IOException e)
{
e.printStackTrace();
}
}
void incrementString() throws IOException
{
s1 += "a";
s2 += "b";
System.out.println(s1+ "-" + s2 + " " + Thread.currentThread().getName());
}
}
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Жду комментов от бывалых. Спасибо за прочтение)
— у переменной есть мастер копия плюс по копии на каждую нить, которые её используют. Мастер копия синхронизируется с локальной копией нити при входе/выходе в/из блока synchronized. Иногда, например, пустой блок synchronized(lock){} имеет смысл.
у переменных с модификатором volatile локальных копий нет. Все нити работают с мастер копией.
В связи с этим я задумался на одним моментом??? Зачем нужен модификатор volatile, если synchronized обеспечивает постоянное взаимодействие с мастер-копией переменной и поддержанием ее в актуальном состоянии. К тому же в момент выполнения блока synchronized переменную никто не сможет поменять, так как объект будет заблокирован. Если только такой случай, если модифицируемое поле находится за пределами объекта??
volatile решит проблему видимости shared значения для нитей, но не решит проблему атомарности операций. Если одна нить читает, а вторая пишет, то для общедоступного ресурса идеален volatile. Но если два потока считывает и пишет, то ресурс без синхронизации, даже с volatile, будет в неопределенном состоянии. см. "Example 8.3.1.4-1. volatile Fields"
получается в кеше пустая строка и когда
получается