摘要:耐心看完的你或多或少會有收獲并發的核心就是包,而的核心是抽象隊列同步器,簡稱,一些鎖啊信號量啊循環屏障啊都是基于。
耐心看完的你或多或少會有收獲!
Java并發的核心就是 java.util.concurrent 包,而 j.u.c 的核心是AbstractQueuedSynchronizer抽象隊列同步器,簡稱 AQS,一些鎖啊!信號量啊!循環屏障啊!都是基于AQS。而 AQS 又是基于Unsafe的一系列compareAndSwap,所以理解了這塊,并發不再是問題!
希望你已經了解了 Java內存模型
何為 CAS先解釋下何為compareAndSwap,就拿AtomicInteger來舉例了:
// 實際操作的值 private volatile int value; // value 的偏移量 因為 int 是32位,知道首部地址就可以了 private static final long valueOffset; // 靜態初始化塊,通過虛擬機提供的接口,獲得 valueOffset = 12 // 不論你實例化多少個 AtomicInteger 對象,這些對象盡管指向不同的堆內存,但是結構都是一樣的 // 所以初始化一次就好了 static { try { valueOffset = unsafe.objectFieldOffset (AtomicInteger.class.getDeclaredField("value")); } catch (Exception ex) { throw new Error(ex); } } // 只是個封裝方法,起作用的代碼并不在這 // 值得注意的是顯式的 this 和第三個參數 1 public final int getAndIncrement() { return unsafe.getAndAddInt(this, valueOffset, 1); } // 以下是 Unsafe 類 可以直接訪問內存地址,類似指針,所以不安全 // o 就是 getAndIncrement()傳入的 this,也就是 AtomicInteger 實例對象 // offset 內存首部偏移量 // delta 就是那個 1 // 應該是希臘字母 δ /"delt?/ delta 變化量,化學反應中的加熱,屈光度,一元二次方程中的判別式 // 佩服 public final int getAndAddInt(Object o, long offset, int delta) { int v; do { v = getIntVolatile(o, offset); } while (!compareAndSwapInt(o, offset, v, v + delta)); return v; } // 從堆內存獲取最新的 value // 如果不明白,可以先了解下 JMM 和 volatile public native int getIntVolatile(Object o, long offset); // expected 就是這個 v = getIntVolatile(o, offset); // 意思就是,我給你這個最新的 value,它要是現在 在內存中還是這個值 那你就返回 true,并且把這塊內存上值更新為 x // 不然的話,我就一直 while (!compareAndSwapInt(o, offset, v, v + delta)); // 相當于自旋鎖 活鎖,不要被高大上的術語嚇到 就是活的循環,不會像死鎖那樣線程 hang 住 public final native boolean compareAndSwapInt(Object o, long offset, int expected, int x);何為 Lock
知道了CAS就可以進一步的說說ReentrantLock, 如果不曾了解Java對象結構,建議先了解下 Java 對象的內存結構
AQS的幾個子類,由于方法和功能不一,在同步處理的細節上可能不一樣。但是,原理都是一樣的,離不開上述的CAS
// 我先簡單解釋一下 synchronized 工作原理 首先它含有 monitorenter 和 monitorexit 兩條指令 // Java 中的每個對象都有自己的 Monitor(由HotSpot c++ 實現) // 當某個線程進入加鎖的代碼(實際上應該是拿到被加鎖的對象在內存的引用地址) // 會執行 monitorenter 然后將 monitor 置為1,當其它線程訪問該內存時,發現 monitor 不為 0 // 所以其它線程無法獲得 monitor,直到占有 monitor 的線程執行 monitorexit 退出將 monitor 減 1 // 如果占有 monitor 的線程重復進入,monitor 是可以一直累加的(可重入鎖,例如通過遞歸或方法互調) // 了解了 synchronized 基本的工作原理,就會明白為什么會有諸如 nonfairTryAcquire(1) release(1) 的方法 // 這是 AbstractQueuedSynchronizer 類中的字段 // 因為 ReentrantLock 中的內部類 Sync 繼承于 AQS // The synchronization state private volatile int state; // tryLock why ? // 因為不同于 synchronized 的悲觀(我才不管你是不是并發,多線程,聲明了,我就加鎖) // 所以 ReentrantLock 我先 try 一 try 吧!萬一不是多線程并發呢!
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/74934.html
摘要:線程池的作用降低資源消耗。通過重復利用已創建的線程降低線程創建和銷毀造成的資源浪費。而高位的部分,位表示線程池的狀態。當線程池中的線程數達到后,就會把到達的任務放到中去線程池的最大長度。默認情況下,只有當線程池中的線程數大于時,才起作用。 線程池的作用 降低資源消耗。通過重復利用已創建的線程降低線程創建和銷毀造成的資源浪費。 提高響應速度。當任務到達時,不需要等到線程創建就能立即執行...
摘要:在線程處理任務期間,其它線程要么循環訪問,要么一直阻塞等著線程喚醒,再不濟就真的如我所說,放棄鎖的競爭,去處理別的任務。寫鎖的話,獨占寫計數,排除一切其他線程。 回顧 在上一篇 Java并發核心淺談 我們大概了解到了Lock和synchronized的共同點,再簡單總結下: Lock主要是自定義一個 counter,從而利用CAS對其實現原子操作,而synchronized是c++...
摘要:比如需要用多線程或分布式集群統計一堆用戶的相關統計值,由于用戶的統計值是共享數據,因此需要保證線程安全。如果類是無狀態的,那它永遠是線程安全的。參考探索并發編程二寫線程安全的代碼 線程安全類 保證類線程安全的措施: 不共享線程間的變量; 設置屬性變量為不可變變量; 每個共享的可變變量都使用一個確定的鎖保護; 保證線程安全的思路: 1. 通過架構設計 通過上層的架構設計和業務分析來避...
摘要:基礎問題的的性能及原理之區別詳解備忘筆記深入理解流水線抽象關鍵字修飾符知識點總結必看篇中的關鍵字解析回調機制解讀抽象類與三大特征時間和時間戳的相互轉換為什么要使用內部類對象鎖和類鎖的區別,,優缺點及比較提高篇八詳解內部類單例模式和 Java基礎問題 String的+的性能及原理 java之yield(),sleep(),wait()區別詳解-備忘筆記 深入理解Java Stream流水...
閱讀 1755·2021-11-18 13:20
閱讀 1140·2021-10-11 10:59
閱讀 2986·2021-08-24 10:01
閱讀 3499·2019-08-29 14:21
閱讀 3351·2019-08-29 14:15
閱讀 3512·2019-08-26 12:23
閱讀 3342·2019-08-26 11:46
閱讀 3344·2019-08-26 11:35