Являются ли Main1, Main2 потокобезопасными?
В случае Main1
потокобезопасность приложения зависит от того, является ли MyObject
поточно-ориентированным и какие-либо другие потоки работают с ним. Тем не менее, оператор obj.doSomething();
является поточно-ориентированным, при условии, что ничто другое не меняет объект
Фактически, оператор obj.doSomething();
не использует переменную в классе включения. Вместо этого значение этой переменной передается внутреннему классу в скрытом аргументе конструктора. Другая вещь, которая делает этот потокобезопасным, состоит в том, что существует неявная синхронизация между родительским и дочерним потоками, когда создается новый поток. (Ссылка - JLS 17.4.4 Порядок синхронизации ) Эти два факта в совокупности означают, что метод Runnable.run()
получит правильную ссылку и что дочерний поток увидит состояние объекта в точке синхронизации ( или позже).
В случае Main2
применяется то же самое. В этом случае вы просто делаете явно (более или менее) то, что происходит неявно в случае Main1
.
ОБНОВЛЕНИЕ - приведенные выше рассуждения применимы, даже если вы изменяете объект в родительском потоке (согласно вашему обновленному вопросу) перед передачей его в дочерний поток ... из-за неявной синхронизации, о которой я упоминал , (Однако, если родительский поток должен был изменить MyObject
после вызова submit()
, вы столкнулись бы с проблемами безопасности потока.)
Имеют ли смысл Main1 и Main2 по-разному?
Я не знаю, что вы спрашиваете. Если вы спрашиваете, есть ли какая-либо польза от использования внутреннего класса, а не анонимного внутреннего класса ... в этом случае ответ отрицательный. Они ведут себя одинаково в отношении безопасности потоков.
На самом деле, версия Main1
лучше, потому что она проще, более читабельна (для опытного разработчика Java) и более устойчива. Класс Main2
предоставляет поле obj
для другого кода, который потенциально доступен или даже обновлен. Это плохой стиль. Вы можете исправить это, но только добавив больше кода ... что возвращает нас к простоте / читабельности.