JavaRush /Java блог /Архив info.javarush /Немного вопросов по нитям с собственными примерами.
Pegas
34 уровень
Гродно

Немного вопросов по нитям с собственными примерами.

Статья из группы Архив info.javarush
Создал класс 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()); } }
Комментарии (9)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Pegas Уровень 34
21 мая 2016
Попытался детально разобраться с поднятым мной в этой теме вопросом. Что же я понял? И так. Во-первых, volatile(V) является как-бы урезанной версией synchronized(S). При попытке изменить поле, помеченное V, происходит копирование переменной в кеш, ее обработка и обратное копирование в оперативную память. При этом ни одна нить не сможет получить доступ к переменной, помеченной V, если с ней уже работает какая-либо нить (не сможет ее поменять либо взять ее значение). Пометка V дает возможность получить самое актуальное значение поля для каждой нити. Что же касается S, то он блокирует доступ не только к переменной, но и к объекту в момент исполнения метода этого объекта, помеченного S. S в моем понимании дает более широкие возможности по сравнению с V в том случае, если в блоке кода нужно, к примеру, модифицировать поле, а потом в этом же блоке и воспользоваться именно ЭТИМ значением поля, а не другим, которое может присвоить ЭТОМУ полю другая нить. Ведь в случае с V один метод 1-ой нити может изменить поле, а во второй метод, в котором нужно значение, выданное первым методом, может придти уже измененное значение, которое может изменить вторая нить. S-блок этого не допустит.
Жду комментов от бывалых. Спасибо за прочтение)
Pegas Уровень 34
20 мая 2016
Вот интересные и емкие изречения по поводу synchronized и volatile, кому интересно:
— у переменной есть мастер копия плюс по копии на каждую нить, которые её используют. Мастер копия синхронизируется с локальной копией нити при входе/выходе в/из блока synchronized. Иногда, например, пустой блок synchronized(lock){} имеет смысл.
у переменных с модификатором volatile локальных копий нет. Все нити работают с мастер копией.

В связи с этим я задумался на одним моментом??? Зачем нужен модификатор volatile, если synchronized обеспечивает постоянное взаимодействие с мастер-копией переменной и поддержанием ее в актуальном состоянии. К тому же в момент выполнения блока synchronized переменную никто не сможет поменять, так как объект будет заблокирован. Если только такой случай, если модифицируемое поле находится за пределами объекта??
blacky Уровень 23
19 мая 2016
А какой результат ты хотел получить?
volatile решит проблему видимости shared значения для нитей, но не решит проблему атомарности операций. Если одна нить читает, а вторая пишет, то для общедоступного ресурса идеален volatile. Но если два потока считывает и пишет, то ресурс без синхронизации, даже с volatile, будет в неопределенном состоянии. см. "Example 8.3.1.4-1. volatile Fields"
Docktor91 Уровень 40
19 мая 2016
может из-за этого?
volatile String s1 = "";
    volatile String s2 = "";