Безопасен ли е потокът за получаване/задаване на низ?

Да кажем, че имам следното,

public class Foo{
    private String bar;

    public String getBar(){
        return bar;
    }

    public void setBar(String bar){
        this.bar = bar;
    }
}

Тези методи автоматично ли са безопасни за нишки поради неизменния характер на класа String или е необходим някакъв механизъм за заключване?


person mre    schedule 25.02.2013    source източник
comment
Предполагам, че имате предвид String в сетера.   -  person Theodoros Chatzigiannakis    schedule 25.02.2013
comment
@TheodorosChatzigiannakis, Да, моя грешка! Фиксиран.   -  person mre    schedule 25.02.2013
comment
Свързан c# въпрос: stackoverflow.com/questions/ 3595114/   -  person PermGenError    schedule 25.02.2013
comment
String обектът е, но не окончателната препратка към него не е. Вижте stackoverflow.com/a/6060405/1812922 за повече подробности   -  person alldayremix    schedule 25.02.2013


Отговори (4)


Не, това не е безопасно за нишки. Foo е променлив, така че ако искате да сте сигурни, че различните нишки виждат една и съща стойност на bar – тоест последователност – или:

  • Направете bar volatile или
  • Направете методите synchronized или
  • Използвайте AtomicReference<String>.

Четенията и записите на bar сами по себе си са атомарни, но атомарността не е безопасност на нишката.

http://docs.oracle.com/javase/tutorial/essential/concurrency/atomic.html


За задълбочено покритие на Java concurrency вземете копие на Java Паралелност на практика (известен още като JCIP).

person Matt Ball    schedule 25.02.2013
comment
+1 Или просто декларирайте bar като final, така че препратката да не може да бъде преназначена на друга стойност. Разбира се, тогава няма да има сетер :) - person Eng.Fouad; 25.02.2013
comment
Това е неизменно. В този случай няма нужда от сетер. И трябва да сте сигурни, че сте предоставили конструктор за инициализиране на стойността, защото в този случай не можете да я промените, след като излезете от конструктора. - person duffymo; 25.02.2013
comment
... От любопитство има ли значение някое от тези? Искам да кажа, че ако действителният ви проблем е състояние на състезание, това все още може да се случи, въпреки volatile или synchronized - това просто намалява „прозореца“, в който може да се случи, нали? Или пропускам нещо тук? - person Clockwork-Muse; 25.02.2013
comment
@Clockwork-Muse и какви условия за състезание би било това? TBH, въпроси като тези са причината, поради която избягвам да споделям променливи (неконкурентни библиотеки) обекти в нишките, доколкото е възможно. - person Matt Ball; 25.02.2013
comment
Първата нишка се актуализира bar непрекъснато. Втора нишка чака bar да прочете като някаква стойност (просто се върти с while(...) цикъл, да речем). Състезателното условие е втора нишка да прочете стойността на bar, преди нишка една да я актуализира отново. Въпреки че всяка от тези опции гарантира, че всички нишки имат една и съща вътрешна препратка (въпреки че препратките са атомарни независимо), това няма значение дали те работят върху обекта по различно време -филии. И да, неща като тези са причината да предпочитам неизменни обекти. - person Clockwork-Muse; 25.02.2013
comment
@Matt Ball, ако вместо това полето String беше променливо, тогава volatile не направи ли нишката на класа безопасна? - person gstackoverflow; 02.02.2017

Вие задавате препратки и като такава неизменността на String не влиза в действие. Вие не засягате съдържанието на String.

person Brian Agnew    schedule 25.02.2013

Не, не е безопасно.

Това е променливо поведение на Foo; Неизменността на низа не се натрупва към Foo.

public class Foo{
    private String bar;

    public synchronized String getBar(){
        return bar;
    }

    public synchronized void setBar(String bar){
        this.bar = bar;
    }
}
person duffymo    schedule 25.02.2013
comment
+1 Какво ще кажете за синхронизирането на getBar()? Може би някоя нишка задава нова стойност на bar, докато другите нишки четат bar. - person Eng.Fouad; 25.02.2013
comment
Съжалявам, нямате смисъл за мен. Мисля, че вашите коментари само объркват проблема. - person duffymo; 25.02.2013
comment
@duffymo несинхронизиран гетер със синхронизиран сетер гарантира ли последователност в нишките? - person Matt Ball; 25.02.2013
comment
@duffymo както го имате сега, инструментът за получаване трябва да бъде синхронизиран, за да се гарантира, че текущото състояние на bar е видимо за всички нишки - person Steve Kuo; 26.02.2013

Не, не е безопасно за нишки.

Докато String е неизменно, проблемът идва от полето на Foo. За да направите това по-очевидно, разгледайте например метод, чиято задача би била да добавя (вместо да заменя) стойността на bar. Когато се извиква от множество нишки, някои записи могат да бъдат загубени. Същото (загубени записи) може да се случи и с вашия прост сетер, дори ако първоначално не е очевидно в този случай.

person Theodoros Chatzigiannakis    schedule 25.02.2013