并發(fā)編程之美-1

主要用來記錄一些自己覺得重點的知識

不定期更新讀書筆記 歡迎關注拄踪、點贊 ??

[TOC]

馬桶??Java 上廁所就能看完的小知識! 歡迎關注、點贊 持續(xù)更新!

第一章

synchronized

Java中Synchronized的用法

synchronized是Java中的關鍵字贸人,是一種同步鎖。

  1. 修飾一個代碼塊佃声,被修飾的代碼塊稱為同步語句塊艺智,其作用的范圍是大括號{}括起來的代碼,作用的對象是調用這個代碼塊的對象圾亏;

2. 修飾一個方法十拣,被修飾的方法稱為同步方法,其作用的范圍是整個方法志鹃,作用的對象是調用這個方法的對象夭问;
  3. 修改一個靜態(tài)的方法,其作用的范圍是整個靜態(tài)方法曹铃,作用的對象是這個類的所有對象甲喝;
  4. 修改一個類,其作用的范圍是synchronized后面括號括起來的部分铛只,作用主的對象是這個類的所有對象。

一個線程訪問一個對象的同步代碼塊時糠溜,別的線程可以訪問該對象的非同步代碼塊而不受阻塞淳玩。

synchronized關鍵字不能繼承

在定義接口方法時不能使用synchronized關鍵字


public class ThreadTest {
    public static void main(String[] args) {
        System.out.println("使用關鍵字靜態(tài)synchronized");
        SyncThread syncThread1 = new SyncThread();
        SyncThread syncThread2 = new SyncThread();
        Thread thread1 = new Thread(syncThread1, "SyncThread1");
        Thread thread2 = new Thread(syncThread2, "SyncThread2");
        thread1.start();
        thread2.start();
    }
}
class SyncThread implements Runnable {
    private static int count;

    public SyncThread() {
        count = 0;
    }

    public static synchronized void method() {
        for (int i = 0; i < 5; i ++) {
            try {
                System.out.println(Thread.currentThread().getName() + ":" + (count++));
                Thread.sleep(500);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public synchronized void run() {
        method();
    }
}

線程通知與等待

當一個線程調用一個公共變量的wait()時非竿,該調用的線程會被阻塞掛起蜕着。

調用 wait() 方法的線程需要事先獲取該對象的監(jiān)視器鎖。否則會拋出異常。

該調用線程會被阻塞掛起時只有通過以下情況才能返回

  1. 線程調用了該共享對象 notify()或者 notifyAll(0方法

  2. 其他線程調用了該線程 interrupt() 方法,該線程拋出 nterruptedException 異常返回承匣。

sleep()調用線程會暫時讓出指定時間的**執(zhí)行權**蓖乘,也就是在這期間不參與CPU的調度,但是程所擁有的監(jiān)視器源韧骗,比如**鎖**還是持有**不讓出**的嘉抒。獲取到 CPU 資源后就可以繼續(xù)運行了。

yield()一般很少使用這個方法袍暴,在調試或者測試時這個方法或許可以幫助復現(xiàn)由于并發(fā)競爭條件導致的問題些侍,其在設計并發(fā)控制時或許會有用途。

sleep方法與yield方法的區(qū)別在于政模,當線程調用sleep方法時調用線程會被阻塞掛起指定的時間岗宣,在這期間線程調度器不會去調度該線程。

而調用yield方法時淋样,線程只是讓出自己剩余的時間片耗式,并沒有被阻塞掛起,而是處于就緒狀態(tài)趁猴,線程調度器下一次調度時就有可能調度到當前線程執(zhí)行刊咳。

線程中斷

Java 中的線程中斷是種線程間的協(xié)作模式,通過設置線程的中斷標志并不能直接終止該線程的執(zhí)行躲叼,而是根據(jù)被中斷的線程根據(jù)中斷狀態(tài)自行處理芦缰。

interrupt() : 設置線程中斷標志為true

isinterrupted():檢測調用線程是否被中斷 不會清除中斷標志

interrupted(): 檢測當前線程是否被中斷 會清除中斷標志 靜態(tài)方法

 @Override
    public void run() {
        //如果當前線程被中斷則退出循環(huán) 則退出線程
        while (!Thread.currentThread().isInterrupted() && count < 10) {
            method();
        }

    }

當一個線程阻塞時間過長時,我們可以通過設置中斷強制拋出異常而返回枫慷,使線程重新進入激活狀態(tài)让蕾。

例如:休眠3s 但是發(fā)現(xiàn)3s內就能滿足條件。如果一直等待3s就會浪費時間或听。調用中斷強制激活探孝。

守護線程與用戶線程

Java 中的線程分為兩類,分別為 daemon 線程(守護線程)和 user 線程(用戶線程)誉裆。

JVM啟動會調用main函數(shù),其所在的錢程就是一個用戶線程顿颅,其實在 JVM內部同時還啟動了好多守護線程,比如垃圾回收線程足丢。

區(qū)別:當最后一個非護線程結束時JVM正常退出粱腻,而不管當前是否存在守護線程,也就是說守護線程是否結束并不影響 JVM 退出斩跌。

當Main線程運行結束后绍些,JVM會啟動一個叫做DestroyJava VM的線程,該線程會等待所有用戶線程結束后終止JVM進程耀鸦。

ThreadLocal

ThreadLocal JDK 包提供的柬批,它提供了線程本地變量啸澡,也就是如果你創(chuàng)建了ThreadLocal ,那么訪問這個變量的每個線程都會有這個變量的一個本地副本氮帐,當多個線程操作這個變量時嗅虏,實際操作的是自己本地內存里面變量,從而避免了線程安全問題上沐。

獲取資源模型

實現(xiàn)原理

每次操作的都是線程內部的ThreadLocalMap皮服,每個線程的本地變量不是存放在 ThreadLocal 里面,而是存放在調用線程的threadLocals變量里奄容,Thr adLocal 就是個工具殼冰更。

key 為我們定義的ThreadLocal變量this引用, value則為使用set方法設置的值昂勒。

具體實現(xiàn)
    public void set(T value) {
        //獲取當前線程
        Thread t = Thread.currentThread();
        // 將當前線程作為 key 蜀细,去查找對應的線手呈交量,找到則設置
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            map.set(this, value);
        } else {
         // 沒有第一次創(chuàng)建對應MAP   
            createMap(t, value);
        }
    }

    ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }

第二章

什么是多線程并發(fā)編程

并發(fā)是指同一個時間段內多個任務同時都在執(zhí)行戈盈。

并行是說在單位時間內多個任務同時在執(zhí)行奠衔。

synchronized

synchronized 塊是 Java 提供的一種原子性內置鎖,當阻塞一個線程時塘娶,需要從用戶態(tài)切換到內核態(tài)執(zhí)行阻塞操作归斤,這是很耗時的操作。會帶來線程調度開銷刁岸。

進入synchronized塊的內存語義是把在 synchronized塊內使用到的變量從線程的工作內存清除脏里,這樣在synchronized塊內使用到該變時就不會從線程的工作內存中獲取,而是直接從主內存中獲取虹曙。

退出synchronized塊的內存語義是把在synchronized塊內對共享變量修改刷新到主內存迫横。

volatile

當一個變量被聲明為volatile時,線程在寫入變量時不會把值緩存在寄存器或者其他地方酝碳,而是會把值刷新回主內存當其它線程讀取該共享變量矾踱,會從主內存重新獲取最新值,而不是使用當前線程的工作內存中的值疏哗。

什么時候使用呛讲?

寫入變量不依賴變量的當前值時,因為如果依賴當前值返奉,將是獲取贝搁、計算、寫入三步操作

這三步操作不是原子性的芽偏,而 volatile 不保證原子性雷逆。例如(count++ 讀取count的值到工作內存,計算count值哮针,再將count刷新進主內存。)

Unsafe

jdk提供的不安全的功能,更低層(c語言)十厢,因為是通過可以直接調用內存不直接提供給用戶使用等太。可以進行數(shù)組邊界判斷與比較與交換CAS操作進行賦值蛮放。官方不推薦使用缩抡。

想要使用只能使用反射獲取變量

getUnsafe()代碼要求必須通過BootStrapClassLoader 加載,而我們使用main函數(shù)調用會使用AppClassLoader調用得所以無法獲取

    @CallerSensitive
    public static Unsafe getUnsafe() {
        Class<?> caller = Reflection.getCallerClass();
        if (!VM.isSystemDomainLoader(caller.getClassLoader()))
            throw new SecurityException("Unsafe");
        return theUnsafe;
    }

示例

public class UnsafeTest {
    static Unsafe unsafe;
    private static long countOffset;
    private int count = 1;
    static {
        //使用反射獲取Unsafe 的成員交量thUnsafe
        try {

            Field field = Unsafe.class.getDeclaredField("theUnsafe");
//           給權限防止禁止反射使用
            field.setAccessible(true);
            unsafe= (Unsafe) field.get(null);
//            設置count參數(shù)偏移量
            countOffset =  unsafe.objectFieldOffset(UnsafeTest.class.getDeclaredField("count"));
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        UnsafeTest unsafeTest = new UnsafeTest();
        int andAddInt = unsafe.getAndAddInt(unsafeTest, countOffset, 2);
//        原值
        System.out.println(andAddInt);
//        新值
        System.out.println(unsafeTest.count);
    }

}

樂觀鎖與悲觀鎖

悲觀鎖指對數(shù)據(jù)被外界修改持保守態(tài)度包颁,認為數(shù)據(jù)很容易就會被其他線程修改瞻想,所以在數(shù)據(jù)被處理前先對數(shù)據(jù)進行加鎖,并在整個數(shù)據(jù)處理過程中娩嚼,使數(shù)據(jù)處于鎖定狀態(tài)蘑险。

樂觀鎖 相對悲觀鎖來說的,它認為數(shù)據(jù)在一般情況下不會造成沖突岳悟,所以在訪問記錄前不會加排它鎖佃迄,而 在進行數(shù)據(jù)提交更新時,才會正式對數(shù)據(jù)沖突與否進行檢測 贵少。

獨占鎖與共享鎖

獨占鎖保證任何時候都只有一個線程能得到鎖呵俏, ReentrantLock 就是以獨占方式實現(xiàn)共享鎖則可以同時由多個線程持有 ,例如 ReadWriteLock 鎖滔灶,它允許一個資源可以被多線程同時進行讀操作普碎。

獨占鎖是一種悲觀鎖,由于每次訪問資源都先加上互斥鎖录平,這限制了并發(fā)性麻车,因為操作并不會影響數(shù)據(jù)的一致性 ,而獨占鎖只允許在同一時間由一個線程讀取數(shù)據(jù)萄涯,其他線程必須等待當前線程釋放鎖才能進行讀取绪氛。

共享鎖則是一種樂觀鎖,它放寬了加鎖的條件涝影,允許多個線程同時進行讀操作枣察。

自旋鎖

當一個線程在獲取鎖(比如獨占鎖)失敗后,會被切換到內核狀態(tài)而被掛起燃逻。

當該線程獲取到鎖時又需要將其切換到內核狀態(tài)而喚醒該線程序目,而從用戶狀態(tài)切換到內核狀態(tài)的開銷是比較大的,在一定程度上會影響并發(fā)性能伯襟。

自旋鎖則是猿涨,當前線程在獲取鎖時,如果發(fā)現(xiàn)鎖已經(jīng)被其他線程占有姆怪,它不馬上阻塞自己叛赚,在不放棄 CPU 使用權的情況下澡绩,多次嘗試獲取默認次數(shù)是 10,很有可能在后面幾次嘗試中其他線程己經(jīng)釋放了鎖俺附,如果嘗試指定的次數(shù)后仍沒有獲取到鎖則當前線程才會被阻塞掛起肥卡。由此看來自旋鎖是使用CPU 時間換取線程阻塞與調度的開銷,但是很有可能這些CPU時間白白浪費事镣。所以選擇獲取鎖釋放鎖快的步鉴。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市璃哟,隨后出現(xiàn)的幾起案子氛琢,更是在濱河造成了極大的恐慌,老刑警劉巖随闪,帶你破解...
    沈念sama閱讀 216,692評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件阳似,死亡現(xiàn)場離奇詭異,居然都是意外死亡蕴掏,警方通過查閱死者的電腦和手機障般,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,482評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來盛杰,“玉大人挽荡,你說我怎么就攤上這事〖垂” “怎么了定拟?”我有些...
    開封第一講書人閱讀 162,995評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長逗嫡。 經(jīng)常有香客問我青自,道長,這世上最難降的妖魔是什么驱证? 我笑而不...
    開封第一講書人閱讀 58,223評論 1 292
  • 正文 為了忘掉前任延窜,我火速辦了婚禮,結果婚禮上抹锄,老公的妹妹穿的比我還像新娘逆瑞。我一直安慰自己,他們只是感情好伙单,可當我...
    茶點故事閱讀 67,245評論 6 388
  • 文/花漫 我一把揭開白布获高。 她就那樣靜靜地躺著艾船,像睡著了一般袍冷。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上聊闯,一...
    開封第一講書人閱讀 51,208評論 1 299
  • 那天布疼,我揣著相機與錄音摊趾,去河邊找鬼币狠。 笑死,一個胖子當著我的面吹牛砾层,可吹牛的內容都是我干的总寻。 我是一名探鬼主播,決...
    沈念sama閱讀 40,091評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼梢为,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了轰坊?” 一聲冷哼從身側響起铸董,我...
    開封第一講書人閱讀 38,929評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎肴沫,沒想到半個月后粟害,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,346評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡颤芬,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,570評論 2 333
  • 正文 我和宋清朗相戀三年悲幅,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片站蝠。...
    茶點故事閱讀 39,739評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡汰具,死狀恐怖,靈堂內的尸體忽然破棺而出菱魔,到底是詐尸還是另有隱情留荔,我是刑警寧澤,帶...
    沈念sama閱讀 35,437評論 5 344
  • 正文 年R本政府宣布澜倦,位于F島的核電站聚蝶,受9級特大地震影響,放射性物質發(fā)生泄漏藻治。R本人自食惡果不足惜碘勉,卻給世界環(huán)境...
    茶點故事閱讀 41,037評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望桩卵。 院中可真熱鬧验靡,春花似錦、人聲如沸吸占。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,677評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽矾屯。三九已至兼蕊,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間件蚕,已是汗流浹背孙技。 一陣腳步聲響...
    開封第一講書人閱讀 32,833評論 1 269
  • 我被黑心中介騙來泰國打工产禾, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人牵啦。 一個月前我還...
    沈念sama閱讀 47,760評論 2 369
  • 正文 我出身青樓亚情,卻偏偏與公主長得像,于是被迫代替她去往敵國和親哈雏。 傳聞我的和親對象是個殘疾皇子楞件,可洞房花燭夜當晚...
    茶點故事閱讀 44,647評論 2 354

推薦閱讀更多精彩內容