2010-09-22 2 views
0

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

Любые другие факторы повлияют на безопасность потока?

**** Поймите, если вы можете привести пример. Спасибо! ** **

+0

Пример чего? –

+0

@ Erick Robertson - пример, который решает каждую проблему когда-либо! :) – willcodejavaforfood

+1

@willcodejavaforfood - Был бы признателен, если может предоставить этот пример. Благодаря! –

ответ

7

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

Стоит сказать, что создание большого приложения, которое ТОЛЬКО использует неизменяемые объекты для обеспечения безопасности потоков, будет затруднено.

Это сложный вопрос, и я бы порекомендовал вам прочитать Java Concurrency in Practice , который является очень хорошим местом для начала.

+0

Не сложно само по себе, но необходимо твердое понимание FP и использование функционального языка делает его гораздо менее болезненным. – delnan

+0

На самом деле, можно создать объект таким образом, чтобы он не был потокобезопасным. Запуск потока из конструктора является хорошим способом нарушения безопасности потоков, например, если новый поток ссылается на объект, который вы еще не завершили. –

+0

@Bill Michell - Да, и это то, что покрывается Java Concurrency in Practice. Вы должны знать, как использовать это в consturctor. – willcodejavaforfood

3

Это правда. Проблема в том, что для вашего приложения достаточно серьезное ограничение только для использования неизменяемых типов данных. У вас не может быть постоянных объектов с состоянием, которое существует в потоках.

Я не понимаю, почему вы хотите это сделать, но это не делает его менее правдивым.

Деталь и пример: http://www.javapractices.com/topic/TopicAction.do?Id=29

2

Если каждый переменная неизменна (не изменился, как только назначено) вы бы действительно есть тривиальную поточно-программу.

Functional programming Окружающая среда использует это.

Однако довольно сложно выполнять чисто функциональное программирование на языке, не предназначенном для этого с нуля.

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

Если вы просто заблудились в мире безопасности потоков и параллелизма, я бы сердечно рекомендовал книгу Java Concurrency in Practice от Goetz. Он написан для Java, но на самом деле проблемы, о которых он говорит, актуальны и на других языках, даже если решения этих проблем могут быть разными.

+0

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

+0

На самом деле вопрос задает вопрос о программе, которая использует только неизменяемые типы данных. Есть * способы писать потокобезопасные java-программы с изменяемыми переменными, и JCIP говорит о большинстве из них. Но я верю, что ответил на заданный вопрос. –

0

Неизменимость позволяет обеспечить защиту от определенных вещей, которые могут пойти не так, как с многопоточными корпусами. В частности, это означает, что свойства объекта, видимые одному потоку, не могут быть изменены другим потоком, пока этот первый поток использует его (поскольку ничего не может его изменить, то, очевидно, другой поток не может).

Конечно, это работает только в том случае, если этот объект идет. Если измененная ссылка на объект также разделяется, тогда некоторые случаи ошибок с поперечным потоком могут произойти, если что-то помещает туда новый объект (но не все, так как не имеет значения, работает ли поток на объекте, который уже был заменен , но опять же это может иметь решающее значение).

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

0

Хотя неизменяемые объекты помогают в обеспечении безопасности потоков, вы можете найти «локальные переменные» и «синхронизировать» более практичные для прогонов реального мира.

0

Любая программа, в которой не может изменяться ни один изменяемый аспект состояния программы более чем одним потоком, будет тривиально поточно-безопасным, так как каждый поток также может быть его собственной отдельной программой. Однако полезная многопоточность, как правило, требует взаимодействия между потоками, что подразумевает существование некоторого изменчивого общего состояния.

Ключом к безопасной и эффективной многопоточности является включение изменчивости на правый «уровень проектирования». В идеале каждый аспект состояния программы должен быть представлен одной неизменяемой (*), изменяемой ссылкой на объект, наблюдаемое состояние которого неизменено. Только один поток за раз может попытаться изменить состояние, представленное определенной изменяемой ссылкой. Эффективная многопоточность требует, чтобы «изменяемый уровень» в состоянии программы был достаточно низким, чтобы разные потоки могли использовать разные части. Например, если у вас есть неизменяемая структура данных AllCustomers, и два потока одновременно пытались изменить разных клиентов, каждая из них создавала версию структуры данных AllCustomers, которая включала бы свои собственные изменения, но не изменения в другом потоке. Не хорошо. Если AllCustomers были изменчивым массивом объектов CustomerState, однако один поток мог бы работать на AllCustomers[4], а другой работал на AllCustomers[9] без помех.

(*) Корневой путь должен существовать, когда аспект состояния становится релевантным и не должен меняться, пока доступ имеет значение. Например, можно было бы сконструировать AddOnlyList<thing>, которые содержат thing[][] под названием Arr, который был инициализирован до размера 32. Когда добавляется первое, Arr[0] будет инициализироваться с использованием CompareExchange в массив из 16 thing. Следующие 15 вещей пойдут в этом массиве. Когда добавляется 17-я вещь, Arr[1] будет инициализирован с использованием CompareExchange массиву размером 32 (который будет содержать новый элемент и 31 элемент после него). Когда добавляется 49-я штука, Arr[2] будет инициализирован для 64 элементов. Обратите внимание, что в то время как thing сам и массивы, содержащиеся в нем, не будут полностью неизменными, только самый первый доступ к любому элементу будет писать, и как только Arr[x][y] будет ссылаться на что-то, он будет продолжать делать это до тех пор, пока существует Arr.