<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                * ## **重入鎖** 重入鎖也稱遞歸鎖,指的是同一線程外層函數獲得鎖之后 ,內層遞歸函數仍然有獲取該鎖的代碼,但卻不會受到影響,ReentrantLock 和synchronized都是可重入鎖。 ``` class TaskThread implements Runnable { public synchronized void set() { System.out.println(Thread.currentThread().getName() + ":set"); } public synchronized void get() { System.out.println(Thread.currentThread().getName() + ":get"); set(); } @Override public void run() { get(); } } class test { public static void main(String[] args) { TaskThread taskThread = new TaskThread(); Thread t1 = new Thread(taskThread); Thread t2 = new Thread(taskThread); t1.start(); t2.start(); } } ``` 執行結果 ``` Thread-0:get Thread-0:set Thread-1:get Thread-1:set ``` get方法中調用set方法,2個方法都加入了synchronized鎖,但是并沒有產生死鎖的現象。說明set方法能獲取到上層的get的鎖。 * ## **讀寫鎖** ReentrantLock和synchronized都為排它鎖,在同一時刻只允許一個線程訪問鎖資源,而讀寫鎖在同一時刻可以允許多個讀線程訪問,在寫線程訪問的時候其他的讀線程和寫線程都會被阻塞,讀寫鎖維護一對鎖(讀鎖和寫鎖),通過鎖的分離,使得并發性提高,適用于讀多寫少的應用場景。 ``` ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); // 讀鎖 Lock r = rwl.readLock(); // 寫鎖 Lock w = rwl.writeLock(); ``` * ## **悲觀鎖與樂觀鎖** ### 樂觀鎖 不會上鎖的一種鎖,通常采用添加version版本字段的方式,每次修改前都會對比版本號,修改后version+1 ### 悲觀鎖 每次讀取數據都認為其他線程會修改數據,所以都會加鎖,synchronized也算是悲觀鎖,還有數據庫的行鎖,讀鎖,寫鎖也都是悲觀鎖。 * ## **原子類** 線程安全的3大特性之一就是原子性,要想保證線程原子性,我們通常會采用加入synchronized的方式。但是synchronized鎖會產生阻塞,必定會影響程序性能。對于一些相對標準化的共享變量的多線程操作,比如i++等,java并發包提供了一種更加有效率的方式.。 ``` private AtomicInteger count = new AtomicInteger(); ... count.incrementAndGet() ... ``` 通過創建AtomicInteger對象,調用incrementAndGet方法就能實現線程安全的非阻塞式的原子操作,java.util.concurrent.atomic原子操作工具包中還提供了很多其他類型的操作做。 ``` AtomicInteger AtomicBoolean AtomicLong AtomicReference ``` 這些原子類中都是用了無鎖的概念,大多使用CAS無鎖機制來實現底層原理。 * ## **CAS無鎖機制** CAS是英文單詞**Compare And Swap**的縮寫,翻譯過來就是比較并替換。 CAS的三個核心參數CAS(V,E,N): ``` 1. 內存地址V:共享變量的內存地址,jmm模型中可以理解為共享變量存放在主內存中值。 2. 預期值E:jmm模型中可以理解為保存在線程本地緩存中的值。 3. 新值N:線程經過運算后,即將要寫入到主內存中的值。 ``` CAS機制中,更新一個變量的時候,只有當變量的預期值E和內存地址V當中的實際值相同時,才會將內存地址V對應的值修改為N。舉個例子: ``` 1.在內存地址V當中,存儲著值為5的變量。 2.此時線程1想要把變量的值增加1。對線程1來說,預期值E=5,要修改的新值N=6。 3.但是,在線程1要提交更新之前,另一個線程2把內存地址V中的變量值率先更新成了6。 4.此時,線程1開始提交更新,首先進行E和地址V的實際值比較(Compare),發現E不等于V的實際值,提交失敗。 5.線程1重新獲取內存地址V的當前值,并重新計算想要修改的新值。此時對線程1來說,E=6,N=7。 6.這一次比較幸運,沒有其他線程改變地址V的值。線程1進行Compare,發現E和地址V的實際值是相等的。 7.線程1進行替換,把地址V的值替換為N,也就是7。 ``` 知道了CAS的執行機制,再來分析`AtomicInteger `的源碼 ``` public class AtomicInteger extends Number implements java.io.Serializable { private static final long serialVersionUID = 6214790243416807050L; // 用來實現CAS機制的實例 private static final Unsafe unsafe = Unsafe.getUnsafe(); // 共享變量在主內存中偏移量,可以理解是V值 private static final long valueOffset; static { try { valueOffset = unsafe.objectFieldOffset (AtomicInteger.class.getDeclaredField("value")); } catch (Exception ex) { throw new Error(ex); } } private volatile int value; ... // 自增的方法 public final int incrementAndGet() { return unsafe.getAndAddInt(this, valueOffset, 1) + 1; } ... } ``` 再來看`getAndAddInt`方法的內部實現 ``` // 原生方法實現CAS算法 public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5); // 原生方法獲取期望值E public native int getIntVolatile(Object var1, long var2); public final int getAndAddInt(Object var1, long var2, int var4) { int var5; do { // 調用原生方法獲取期望值E var5 = this.getIntVolatile(var1, var2); } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4)); return var5; } ``` 代碼可以理解為 ``` do { 獲取期望值E } while(!CAS(內存地址V, 期望值E, 新值N)); return 期望值E; ``` CAS機制的缺點 問題:如果變量V初次讀取的時候是5,并且在準備賦值的時候檢查到它仍然是5,那能說明它的值沒有被其他線程修改過了嗎? 如果在這段期間曾經被改成6,然后又改回5,那CAS操作就會誤認為它從來沒有被修改過。但是這對當前線程的執行會有影響嗎???? * ## **Synchronized實現原理** 未完待續,貌似挺復雜 * ## **Lock實現原理與AQS** 未完待續,貌似挺復雜 * ## **自旋鎖** 自旋鎖不會引起調用者睡眠,如果自旋鎖已經被別的執行單元保持,調用者就一直循環在那里,會持續占用CPU資源,自旋鎖適用于鎖使用者保持鎖時間比較短的情況。CAS屬于自旋鎖模式 * ## **Disruptor并發框架** 能夠在一個線程里每秒處理6百萬訂單的開源并發框架。附上鏈接 [http://ifeve.com/disruptor/](http://ifeve.com/disruptor/)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看