[Java 并發(fā)]并發(fā)編程實(shí)戰(zhàn)筆記-對象的共享

java 對象的共享

要編寫正確的并發(fā)程序革半,關(guān)鍵在于在訪問共享可變狀態(tài)是需要進(jìn)行正確的管理,下面介紹如何共享和發(fā)布對象,從而使他們能夠安全的有多線程同時(shí)訪問虾攻。

volatile

加鎖機(jī)制既可以確保可見性有可以確保原子性更鲁,而volatile變量只能確宾浚可見性。

典型用法

    volatile boolean asleep;
    ...
    while (!asleep)
      countSomeSheep();

非原子的64位操作

jvm起初設(shè)計(jì)的時(shí)候64位計(jì)算并不是普遍的澡为,大部分機(jī)器還是32位的朋沮。在32位機(jī)器上計(jì)算long類型時(shí),其實(shí)是分成高位和低位分別計(jì)算缀壤,在把結(jié)果返回樊拓。但是jvm規(guī)范并沒有強(qiáng)制要求這個(gè)操作時(shí)原子性的,所以在并發(fā)場景下塘慕,一個(gè)線程讀到的long可能是另一個(gè)線程只計(jì)算了高位或低位的結(jié)果筋夏。為了避免這樣的操作,需要把這個(gè)變量聲明稱volatile图呢。

 volatile long l;

發(fā)布與溢出

先看一個(gè)例子

 //  BAD
class UnsafeStates {
  private String[] states = new String[] {"AK", "AL" ...  };
  public String[] getStates() { return states; }
}

上面的方法直接把內(nèi)部變量引用返回条篷,造成了內(nèi)部變量溢出骗随。正確的方式應(yīng)該是:

 //  GOOD
class UnsafeStates {
    private String[] states = new String[]{"AK", "AL"};
    public String[] getStates() {
        // 返回副本,這樣就不會影響內(nèi)部
        String[] tmp = new String[states.length];
        System.arraycopy(states, 0, tmp, 0, states.length);
        return tmp;
    }
}

封接能夠使得對程序的可見性進(jìn)行分析變得可能赴叹,并使得無意中破壞設(shè)計(jì)約束條件變得更雄鸿染。

   // BAD
    public class ThisEscape {
        public ThisEscape(EventSource source) {
            source.registerListener(
                    new EventListener() {
                        public void onEvent(Event e) {
                            doSomething(e);
                        }
                    });
        }
    }

上面的例子隱式的提前暴露了this對象(在對象構(gòu)造完成之前,或者說在構(gòu)造方法中暴露了當(dāng)前對象的引用)乞巧。在構(gòu)造方法完成之前涨椒,當(dāng)前對象的處于不可預(yù)測和不一致的狀態(tài),this對象提前暴露绽媒,超出了它的所用范圍蚕冬。正確的方法是可以把對象引用保存到變量中,等構(gòu)造方法完成后在調(diào)用是辕,如下囤热;

    // GOOD
    public class SafeListener {
        private final EventListener listener;
        private SafeListener() {
            listener = new EventListener() {
                public void onEvent(Event e) {
                    doSomething(e);
                }
            };
        }
        public static SafeListener newInstance(EventSource source) {
            SafeListener safe = new SafeListener();
            source.registerListener(safe.listener);
            return safe;
        }
    }

安全對象的構(gòu)造過程

線程封閉

當(dāng)訪問共享的可變數(shù)據(jù)室,通常需要使用同步获三。一種避免使用同步的方式就是不同享數(shù)據(jù)旁蔼。如果僅在但相成內(nèi)訪問數(shù)據(jù),就不需要同步疙教。折中技術(shù)被稱為線程封閉(Thead Confinement)棺聊,他是實(shí)現(xiàn)線程安全性的最簡單方式之一。

一種常見的應(yīng)用是JDBC的Connection對象松逊。JDBC規(guī)范并不要求Connecting對象必須是線程安全的躺屁。在典型的服務(wù)器應(yīng)用程序中,線程從連接池中獲得一個(gè)Connectiion對象经宏,并且用改對象來處理請求犀暑,使用完成后在將對象返回給連接池。由于大多數(shù)請求(servlet請求)都是有單個(gè)線程采用同步方式來處理烁兰,并且在Connection對象返回之前耐亏,連接池不會再將它分配給其他線程,因此沪斟,折中連接管理模式在處理請求是隱含地將Connection對象封閉在線程中广辰。

Java語言中無法強(qiáng)制將對象封閉在某個(gè)線程中,這是程序設(shè)計(jì)需要考慮的因素主之。Java好辛苦提供了一些機(jī)制幫助維持線程封閉性择吊,例如局部變量和ThreadLocal類,即便如此槽奕,程序員仍然需要負(fù)責(zé)確保封閉在線程中的對象不會從線程中溢出几睛。

Ad-hoc 線程封閉

維護(hù)線程封閉性的職責(zé)完全由程序?qū)崿F(xiàn)來承擔(dān),ad-hoc線程封閉式非常脆弱的粤攒,因?yàn)闆]有任何一種語言特性支持他所森。事實(shí)上囱持,對線程封閉對象(例如,GUI應(yīng)用程序中的可視化組建或數(shù)據(jù)模型等)的引用通常保存在公有變量中焕济。

由于Ad-hoc線程封閉技術(shù)的脆弱性纷妆,因此在線程中盡量少用他,在可能的情況下晴弃,應(yīng)該使用更強(qiáng)的線程封閉技術(shù)(例如掩幢,棧封閉或ThreadLocal類)。

棧封閉

棧封閉式一個(gè)對象只能通過本地變量訪問肝匆。就像封裝更容易保存不變量粒蜈,本地變量可以更容易限定線程對變量的訪問顺献。本地變量的本質(zhì)是限定在當(dāng)前線程內(nèi)旗国,他存在于執(zhí)行線程棧中,不能被其他線程訪問注整。棧封閉(又叫 within-thread 或 thread-local能曾,不要和ThreadLocal類混了)更容易維護(hù)并且比Ad-hoc線程封閉更強(qiáng)壯。

通俗一點(diǎn)講肿轨,本地變量是變量作用域最小的寿冕,在開發(fā)多線程程序是應(yīng)該盡量減小變量的作用域。

不變性

如果一個(gè)對象發(fā)布以后不會發(fā)生變化椒袍,那么在訪問他的時(shí)候就不用考慮線程安全問題了驼唱。

**不可變對象一定是線程安全的 **

當(dāng)滿足一下條件時(shí),對象才是不可變的:

  • 對象創(chuàng)建以后七狀態(tài)就不能I許改驹暑。
  • 對象的所有與都是final類型
  • 對象是正確創(chuàng)建的(在對象的創(chuàng)建其間玫恳,this引用沒有溢出)。

安全發(fā)布

上節(jié)講的是如何把對象封閉在線程或另一個(gè)對象的內(nèi)部优俘,確保對象不被發(fā)布京办。

要安全地發(fā)布一個(gè)對象,對象的引用以及對象的狀態(tài)必須同時(shí)對其他線程可見帆焕。一個(gè)正確構(gòu)造的對象可以通過一下方式來安全的發(fā)布:

  • 在靜態(tài)初始化函數(shù)中初始化一個(gè)對象引用
  • 講對象的引用保存到volatile類型的域或者AtomicRefer對象中惭婿。
  • 講對象的引用保存到謳歌正確構(gòu)造對象的final類型域中g(shù)- 講對象的引用保存到一個(gè)有鎖保護(hù)的域中。

可變對象在構(gòu)造后可以叶雹,那么安全發(fā)布只能確辈萍ⅲ“發(fā)布當(dāng)時(shí)”狀態(tài)的可見性。

對象的發(fā)布需求取決于他的可變性:

  • 不可變對象可以通過任意機(jī)制來發(fā)布折晦。
  • 事實(shí)不可變對象必須通過安全方式來發(fā)布
  • 可變對象必須通過安全方式來發(fā)布钥星,必須通過是線程安全的或者有某個(gè)鎖保護(hù)起來。

在并發(fā)程序中使用和共享對象是筋遭,可以使用一些實(shí)用的策略打颤,包括:
線程封閉暴拄。線程封閉的對象只能由一個(gè)線程擁有,對象被封閉在改線程中编饺,并且只能由一個(gè)線程修改乖篷。
制度共享。在沒有額外同步的情況下透且,共享的制度對象可以有多線程并發(fā)訪問撕蔼,但任何線程都不能修改I啊它。共享的制度對象包括不可變對象和事實(shí)不可變對戲那個(gè)秽誊。
線程安全共享鲸沮。線程安全的對象在其內(nèi)部實(shí)現(xiàn)同步,因此多個(gè)線程可以通過對象的共有接口進(jìn)行訪問和不需要進(jìn)一步的同步锅论。
保護(hù)對象讼溺。被保護(hù)的對象只能通過持有特定的鎖來訪問。保護(hù)對象包括封裝在其他線程安全對象中的對象最易,以及已發(fā)布的并且由某個(gè)特定鎖保護(hù)的對象怒坯。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市藻懒,隨后出現(xiàn)的幾起案子剔猿,更是在濱河造成了極大的恐慌,老刑警劉巖嬉荆,帶你破解...
    沈念sama閱讀 217,084評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件归敬,死亡現(xiàn)場離奇詭異,居然都是意外死亡鄙早,警方通過查閱死者的電腦和手機(jī)汪茧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,623評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蝶锋,“玉大人陆爽,你說我怎么就攤上這事“饴疲” “怎么了慌闭?”我有些...
    開封第一講書人閱讀 163,450評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長躯舔。 經(jīng)常有香客問我驴剔,道長,這世上最難降的妖魔是什么粥庄? 我笑而不...
    開封第一講書人閱讀 58,322評論 1 293
  • 正文 為了忘掉前任丧失,我火速辦了婚禮,結(jié)果婚禮上惜互,老公的妹妹穿的比我還像新娘布讹。我一直安慰自己琳拭,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,370評論 6 390
  • 文/花漫 我一把揭開白布描验。 她就那樣靜靜地躺著白嘁,像睡著了一般。 火紅的嫁衣襯著肌膚如雪膘流。 梳的紋絲不亂的頭發(fā)上絮缅,一...
    開封第一講書人閱讀 51,274評論 1 300
  • 那天,我揣著相機(jī)與錄音呼股,去河邊找鬼耕魄。 笑死,一個(gè)胖子當(dāng)著我的面吹牛彭谁,可吹牛的內(nèi)容都是我干的吸奴。 我是一名探鬼主播,決...
    沈念sama閱讀 40,126評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼马靠,長吁一口氣:“原來是場噩夢啊……” “哼奄抽!你這毒婦竟也來了蔼两?” 一聲冷哼從身側(cè)響起甩鳄,我...
    開封第一講書人閱讀 38,980評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎额划,沒想到半個(gè)月后妙啃,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,414評論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡俊戳,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,599評論 3 334
  • 正文 我和宋清朗相戀三年揖赴,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片抑胎。...
    茶點(diǎn)故事閱讀 39,773評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡燥滑,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出阿逃,到底是詐尸還是另有隱情铭拧,我是刑警寧澤,帶...
    沈念sama閱讀 35,470評論 5 344
  • 正文 年R本政府宣布恃锉,位于F島的核電站搀菩,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏破托。R本人自食惡果不足惜肪跋,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,080評論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望土砂。 院中可真熱鬧州既,春花似錦谜洽、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,713評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至晤郑,卻和暖如春敌呈,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背造寝。 一陣腳步聲響...
    開封第一講書人閱讀 32,852評論 1 269
  • 我被黑心中介騙來泰國打工磕洪, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人诫龙。 一個(gè)月前我還...
    沈念sama閱讀 47,865評論 2 370
  • 正文 我出身青樓析显,卻偏偏與公主長得像,于是被迫代替她去往敵國和親签赃。 傳聞我的和親對象是個(gè)殘疾皇子谷异,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,689評論 2 354

推薦閱讀更多精彩內(nèi)容