3. Java多線程同步

Java Synchronized 塊

Synchronized塊是用來解決race condition屿附。Synchronized塊是基于對象碗殷,作用在同一對象的同步快保證在同一時間只有一個線程處理。Synchronized關(guān)鍵字可以作用于一下四種情況:

  • 實(shí)例方法
  • 靜態(tài)方法
  • 實(shí)例方法內(nèi)的代碼塊
  • 靜態(tài)方法內(nèi)的代碼塊

Synchronized Instance Methods

  public synchronized void add(int value){
      this.count += value;
  }

實(shí)例方法加synchronized是同步的其擁有該方法的對象祟霍。如果有多個實(shí)例對象押搪,那么每個對象在同一時間都只能有一個線程執(zhí)行同步方法。

Synchronized Static Methods

  public static synchronized void add(int value){
      this.count += value;
  }

靜態(tài)方法加synchronized是同步其擁有該方法的類浅碾。由于一個JVM里面只有一個類大州,所以在同一個類中只能有一個線程執(zhí)行同步方法。

Synchronized Blocks in Instance Methods

  public void add(int value){
    synchronized(this){
       this.count += value;   
    }
  }

實(shí)例方法內(nèi)的代碼塊通過指定加鎖對象(monitor object)來進(jìn)行同步垂谢。有時候不需要對整個方法加鎖厦画,只需要對方法內(nèi)的一部分加鎖,可以使用該方法滥朱。

Synchronized Blocks in Static Methods

  public class MyClass {

    public static synchronized void log1(String msg1, String msg2){
       log.writeln(msg1);
       log.writeln(msg2);
    }

  
    public static void log2(String msg1, String msg2){
       synchronized(MyClass.class){
          log.writeln(msg1);
          log.writeln(msg2);  
       }
    }
  }

靜態(tài)方法內(nèi)的代碼塊同步的是擁有該方法的類根暑。在上述例子中,一個線程在同一時刻只能執(zhí)行一個方法徙邻。如果log2同步快內(nèi)加鎖的是不同的類排嫌,那么一個線程可以同時執(zhí)行這兩個方法。

Java Volatile關(guān)鍵字

volatile關(guān)鍵字保證變量的可見性

非volatile變量讀取方法

多線程應(yīng)用在處理非volatile變量的時候缰犁,先把變量的值拷貝一份放到cpu cache里面淳地,以此提高效率怖糊。

volatile變量保證每次從main memory里面讀取變量最新的值,每次修改以后將變量的值更新到main memory里面颇象。Java5以后的volatile關(guān)鍵字提供了Happens Before Guarantee

  • 如果線程A寫了一個volatile變量伍伤,接著線程B讀取了同一個volatile變量。那么線程A更新volatile變量之前的所有變量遣钳,在線程B讀取volatile變量之后扰魂,都是可見的。
  • 讀寫volatile變量的操作不能被JVM重新排序蕴茴,但是volatile變量之前和之后的操作可以被重新排序劝评。
public class Exchanger {

    private Object   object       = null;
    private volatile hasNewObject = false;

    public void put(Object newObject) {
        while(hasNewObject) {
            //wait - do not overwrite existing new object
        }
        object = newObject;
        hasNewObject = true; //volatile write
    }

    public Object take(){
        while(!hasNewObject){ //volatile read
            //wait - don't take old object (or null)
        }
        Object obj = object;
        hasNewObject = false; //volatile write
        return obj;
    }
}

可以利用這個特性,不用每個變量都加volatile倦淀。上面的例子中付翁,如果只有一個線程執(zhí)行put(), 另外一個線程執(zhí)行take()晃听,那么不需要同步塊也能保證線程安全。

sharedObject.nonVolatile1 = 123;
sharedObject.nonVolatile2 = 456;
sharedObject.nonVolatile3 = 789;

sharedObject.volatile     = true; //a volatile variable

int someValue1 = sharedObject.nonVolatile4;
int someValue2 = sharedObject.nonVolatile5;
int someValue3 = sharedObject.nonVolatile6;

volatile保證了sharreObject.volatile的順序不被重排砰识,但是前3個變量和后面3個變量的執(zhí)行順序可能被JVM重排能扒。

僅僅volatile是不夠的

只要一個線程需要先讀一個volatile變量,然后在需要在這個變量值的基礎(chǔ)之上生成一個新的值辫狼,那么volatile變量不再試線程安全的初斑。
當(dāng)有多個線程對volatile變量進(jìn)行寫操作的時候,就有可能造成race condition膨处。

volatile變量不保證線程安全

什么時候volatile變量是可靠的

當(dāng)一個線程進(jìn)行volatile變量的讀寫见秤,另外一個變量只進(jìn)行volatile變量的讀的時候,變量是線程安全的額真椿。

volatile變量的性能

由于volatile變量需要從main memory里面讀取數(shù)據(jù)鹃答,多以性能比直接從cpu 緩存中讀取數(shù)據(jù)要高。多以在必要的時候再使用volatile關(guān)鍵字突硝。

ThreadLocal

ThreadLocal類允許生成一個只能被一個線程進(jìn)行讀寫的變量测摔。即使兩個線程執(zhí)行同一段代碼,兩個線程也不能看到對方的ThreadLocal變量

public class ThreadLocalExample {

    public static class MyRunnable implements Runnable {

        private ThreadLocal<Integer> threadLocal =
               new ThreadLocal<Integer>();

        @Override
        public void run() {
            threadLocal.set( (int) (Math.random() * 100D) );
    
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
            }
    
            System.out.println(threadLocal.get());
        }
    }


    public static void main(String[] args) {
        MyRunnable sharedRunnableInstance = new MyRunnable();

        Thread thread1 = new Thread(sharedRunnableInstance);
        Thread thread2 = new Thread(sharedRunnableInstance);

        thread1.start();
        thread2.start();

        thread1.join(); //wait for thread 1 to terminate
        thread2.join(); //wait for thread 2 to terminate
    }

}

在上面的例子中解恰,雖然是同一個ThreadLocal成員變量锋八,但是兩個的值取出來是不相同的。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末护盈,一起剝皮案震驚了整個濱河市挟纱,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌腐宋,老刑警劉巖紊服,帶你破解...
    沈念sama閱讀 219,188評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件檀轨,死亡現(xiàn)場離奇詭異,居然都是意外死亡围苫,警方通過查閱死者的電腦和手機(jī)裤园,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來剂府,“玉大人拧揽,你說我怎么就攤上這事∠僬迹” “怎么了淤袜?”我有些...
    開封第一講書人閱讀 165,562評論 0 356
  • 文/不壞的土叔 我叫張陵菜谣,是天一觀的道長碾篡。 經(jīng)常有香客問我,道長惕医,這世上最難降的妖魔是什么意鲸? 我笑而不...
    開封第一講書人閱讀 58,893評論 1 295
  • 正文 為了忘掉前任烦周,我火速辦了婚禮,結(jié)果婚禮上怎顾,老公的妹妹穿的比我還像新娘读慎。我一直安慰自己,他們只是感情好槐雾,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,917評論 6 392
  • 文/花漫 我一把揭開白布夭委。 她就那樣靜靜地躺著,像睡著了一般募强。 火紅的嫁衣襯著肌膚如雪株灸。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,708評論 1 305
  • 那天擎值,我揣著相機(jī)與錄音慌烧,去河邊找鬼。 笑死鸠儿,一個胖子當(dāng)著我的面吹牛杏死,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播捆交,決...
    沈念sama閱讀 40,430評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼淑翼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了品追?” 一聲冷哼從身側(cè)響起玄括,我...
    開封第一講書人閱讀 39,342評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎肉瓦,沒想到半個月后遭京,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體胃惜,經(jīng)...
    沈念sama閱讀 45,801評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,976評論 3 337
  • 正文 我和宋清朗相戀三年哪雕,在試婚紗的時候發(fā)現(xiàn)自己被綠了船殉。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,115評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡斯嚎,死狀恐怖利虫,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情堡僻,我是刑警寧澤糠惫,帶...
    沈念sama閱讀 35,804評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站钉疫,受9級特大地震影響硼讽,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜牲阁,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,458評論 3 331
  • 文/蒙蒙 一固阁、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧城菊,春花似錦备燃、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽棉胀。三九已至法瑟,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間唁奢,已是汗流浹背霎挟。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留麻掸,地道東北人酥夭。 一個月前我還...
    沈念sama閱讀 48,365評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像脊奋,于是被迫代替她去往敵國和親熬北。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,055評論 2 355

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

  • 從三月份找實(shí)習(xí)到現(xiàn)在诚隙,面了一些公司讶隐,掛了不少,但最終還是拿到小米久又、百度巫延、阿里效五、京東、新浪炉峰、CVTE畏妖、樂視家的研發(fā)崗...
    時芥藍(lán)閱讀 42,253評論 11 349
  • 一、引言 前幾天面試疼阔,被大師虐殘了戒劫,好多基礎(chǔ)知識必須得重新拿起來啊。閑話不多說竿开,進(jìn)入正題谱仪。 二、為什么要線程同步 ...
    coffee_0ca0閱讀 513評論 0 0
  • Java-Review-Note——4.多線程 標(biāo)簽: JavaStudy PS:本來是分開三篇的否彩,后來想想還是整...
    coder_pig閱讀 1,653評論 2 17
  • 每想你一次 天空飄落一粒沙 于是形成了撒哈拉 ...
    柒玖九閱讀 547評論 5 7
  • 手機(jī)里下載了個百度網(wǎng)盤的App列荔,平時拍攝或下載的圖片敬尺,在網(wǎng)絡(luò)環(huán)境下實(shí)時上傳云端,手機(jī)進(jìn)水或主版燒壞贴浙,再也不擔(dān)心歷史...
    初刻杰閱讀 252評論 0 0