<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Java顯式鎖

          共 12501字,需瀏覽 26分鐘

           ·

          2021-06-27 18:50

          點(diǎn)擊上方藍(lán)色字體,選擇“標(biāo)星公眾號(hào)”

          優(yōu)質(zhì)文章,第一時(shí)間送達(dá)

            作者 |  IT王小二

          來(lái)源 |  urlify.cn/biuENr

          一、顯式鎖

          什么是顯式鎖?

          由自己手動(dòng)獲取鎖,然后手動(dòng)釋放的鎖。

          有了 synchronized(內(nèi)置鎖) 為什么還要 Lock(顯示鎖)?

          使用 synchronized 關(guān)鍵字實(shí)現(xiàn)了鎖功能的,使用 synchronized 關(guān)鍵字將會(huì)隱式地獲取鎖,但是它將鎖的獲取和釋放固化了,也就是先獲取再釋放。

          與內(nèi)置加鎖機(jī)制不同的是,Lock 提供了一種無(wú)條件的、可輪詢的、定時(shí)的以及可中斷的鎖獲取操作,所有加鎖和解鎖的方法都是顯式的。

          二、Lock的常用api

          方法名稱描述
          void lock()獲取鎖
          void lockInterruptibly() throws InterruptedException可中斷的獲取鎖,和lock()方法的不同之處在于該方法會(huì)響應(yīng)中斷,即在鎖的獲取中可以中斷當(dāng)前線程
          boolean tryLock()嘗試非阻塞的獲取鎖,調(diào)用該方法后立刻返回,如果能夠獲取則返回true,否則返回false
          boolean tryLock(long time, TimeUnit unit) throws InterruptedException超時(shí)獲取鎖,當(dāng)前線程會(huì)在以下三種情況下會(huì)返回:
          1. 當(dāng)前線程在超時(shí)時(shí)間內(nèi)獲得了鎖
          2.當(dāng)前線程在超市時(shí)間內(nèi)被中斷
          3. 超時(shí)時(shí)間結(jié)束,返回false
          void unlock();釋放鎖

          三、Lock的標(biāo)準(zhǔn)用法

          lock.lock();
          try {
              // 業(yè)務(wù)邏輯
          } finally {
              lock.unlock();
          }
          • 在 finally 塊中釋放鎖,目的是保證在獲取到鎖之后,最終能夠被釋放。

          • 不要將獲取鎖的過(guò)程寫(xiě)在 try 塊中,因?yàn)槿绻讷@取鎖(自定義鎖的實(shí)現(xiàn))時(shí)發(fā)生了異常,異常拋出的同時(shí),也會(huì)導(dǎo)致鎖無(wú)故釋放。

          四、ReentrantLock(可重入鎖)

          Lock接口常用的實(shí)現(xiàn)類是 ReentrantLock。

          示例代碼:主線程100000次減,子線程10萬(wàn)次加。

          public class ReentrantLockTest {

              private Lock lock = new ReentrantLock();
              private int count = 0;

              public int getCount() {
                  return count;
              }

              private static class ReentrantLockThread extends Thread {
                  private ReentrantLockTest reentrantLockTest;

                  public ReentrantLockThread(ReentrantLockTest reentrantLockTest) {
                      this.reentrantLockTest = reentrantLockTest;
                  }

                  @Override
                  public void run() {
                      for (int i = 0; i < 100000; i++) {
                          reentrantLockTest.incr();
                      }
                      System.out.println(Thread.currentThread().getName() + " end, count =  " + reentrantLockTest.getCount());
                  }
              }

              private void incr() {
                  lock.lock();
                  try {
                      count++;
                  } finally {
                      lock.unlock();
                  }
              }

              private void decr() {
                  lock.lock();
                  try {
                      count--;
                  } finally {
                      lock.unlock();
                  }
              }

              public static void main(String[] args) throws InterruptedException {
                  ReentrantLockTest reentrantLockTest = new ReentrantLockTest();
                  new ReentrantLockThread(reentrantLockTest).start();

                  for (int i = 0; i < 100000; i++) {
                      // 遞減100000
                      reentrantLockTest.decr();
                  }
                  System.out.println(Thread.currentThread().getName() + " count =  " + reentrantLockTest.getCount());
              }
          }

          1. 鎖的可重入性

          簡(jiǎn)單地講就是:“同一個(gè)線程對(duì)于已經(jīng)獲得到的鎖,可以多次繼續(xù)申請(qǐng)到該鎖的使用權(quán)”。而 synchronized 關(guān)鍵字隱式的支持重進(jìn)入,比如一個(gè) synchronized 修飾的遞歸方法,在方法執(zhí)行時(shí),執(zhí)行線程在獲取了鎖之后仍能連續(xù)多次地獲得該鎖

          同樣,ReentrantLock 在調(diào)用 lock()方法時(shí),已經(jīng)獲取到鎖的線程,能夠再次調(diào)用lock()方法獲取鎖而不被阻塞

          2. 公平鎖和非公平鎖

          • 如果在時(shí)間上,先對(duì)鎖進(jìn)行獲取的請(qǐng)求一定先被滿足,那么這個(gè)鎖是公平的,反之,是不公平的。公平的獲取鎖,也就是等待時(shí)間最長(zhǎng)的線程最優(yōu)先獲取鎖,也可以說(shuō)鎖獲取是順序的。

          • ReentrantLock 提供了一個(gè)構(gòu)造函數(shù),能夠控制鎖是否是公平的(缺省為不公平鎖)。事實(shí)上,公平的鎖機(jī)制往往沒(méi)有非公平的效率高。

          • 在激烈競(jìng)爭(zhēng)的情況下,非公平鎖的性能高于公平鎖的性能的一個(gè)原因是:在恢復(fù)一個(gè)被掛起的線程與該線程真正開(kāi)始運(yùn)行之間存在著嚴(yán)重的延遲。

          • 假設(shè)線程 A 持有一個(gè)鎖,并且線程 B 請(qǐng)求這個(gè)鎖,由于這個(gè)鎖已被線程 A 持有,因此 B 將被掛起。當(dāng) A 釋放鎖時(shí),B 將被喚醒,因此會(huì)再次嘗試獲取鎖。與此同時(shí),如果 C 也請(qǐng)求這個(gè)鎖,那么 C 很可能會(huì)在 B 被完全喚醒之前獲得、使用以及釋放這個(gè)鎖,這樣的情況是一種“雙贏”的局面:B 獲得鎖的時(shí)刻并沒(méi)有推遲,C 更早地獲得了鎖,完成了自己的任務(wù),然后釋放了鎖,并且吞吐量也獲得了提高。

          五、ReentrantReadWriteLock(讀寫(xiě)鎖)

          ReentrantReadWriteLock 是 ReadWriteLock 的實(shí)現(xiàn)類。

          之前提到鎖基本都是排他鎖,這些鎖在同一時(shí)刻只允許一個(gè)線程進(jìn)行訪問(wèn),而讀寫(xiě)鎖在同一時(shí)刻可以允許多個(gè)讀線程訪問(wèn)但是在寫(xiě)線程訪問(wèn)時(shí),所有的讀線程和其他寫(xiě)線程均被阻塞。讀寫(xiě)鎖維護(hù)了一對(duì)鎖,一個(gè)讀鎖和一個(gè)寫(xiě)鎖,通過(guò)分離讀鎖和寫(xiě)鎖,使得并發(fā)性相比一般的排他鎖有了很大提升。

          讀鎖不排斥讀鎖,但是排斥寫(xiě)鎖;寫(xiě)鎖即排斥讀鎖也排斥寫(xiě)鎖。

          private final ReadWriteLock lock = new ReentrantReadWriteLock();
          private final Lock getLock = lock.readLock(); // 讀鎖
          private final Lock setLock = lock.writeLock(); // 寫(xiě)鎖

          至于上鎖、解鎖與 ReentrantLock 使用方式一致。

          六、Condition

          • 任意一個(gè) Java 對(duì)象,都擁有一組監(jiān)視器方法(定義在 java.lang.Object 上),主要包括 wait()、wait(long timeout)、notify()以及 notifyAll()方法,這些方法與 synchronized 同步關(guān)鍵字配合,可以實(shí)現(xiàn)等待/通知模式。

          • Condition 接口也提供了類似 Object 的監(jiān)視器方法,與 Lock 配合可以實(shí)現(xiàn)等待/通知模式。

          常用api

          方法名稱描述
          void await() throws InterruptedException使當(dāng)前線程進(jìn)入等待狀態(tài)直到被通知(signal)或中斷
          void signal()喚醒一個(gè)等待的線程
          void signalAll()喚醒所有等待的線程

          示例代碼,主線程調(diào)用方法喚醒兩個(gè)子線程。

          public class ConditionTest {

              private volatile boolean flag = false;
              private Lock lock = new ReentrantLock();
              private Condition condition = lock.newCondition();

              private void task1() {
                  lock.lock();
                  try {
                      try {
                          System.out.println(Thread.currentThread().getName() + " 等待中");
                          condition.await();
                      } catch (InterruptedException e) {
                          e.printStackTrace();
                      }
                      System.out.println(Thread.currentThread().getName() + " 等待結(jié)束");
                      System.out.println("發(fā)送郵件");
                  } finally {
                      lock.unlock();
                  }
              }

              private void task2() {
                  lock.lock();
                  try {
                      try {
                          System.out.println(Thread.currentThread().getName() + " 等待中");
                          condition.await();
                      } catch (InterruptedException e) {
                          e.printStackTrace();
                      }
                      System.out.println(Thread.currentThread().getName() + " 等待結(jié)束");
                      System.out.println("發(fā)送短信");
                  } finally {
                      lock.unlock();
                  }
              }

              private void updateFlag() {
                  lock.lock();
                  try {
                      this.flag = true;
                      this.condition.signalAll();
                  }finally {
                      lock.unlock();
                  }
              }

              private static class ConditionThread1 extends Thread {
                  private ConditionTest conditionTest;
                  public ConditionThread1(ConditionTest conditionTest) {
                      this.conditionTest = conditionTest;
                  }

                  @Override
                  public void run() {
                      if (!conditionTest.flag) {
                          conditionTest.task1();
                      }
                  }
              }

              private static class ConditionThread2 extends Thread {
                  private ConditionTest conditionTest;
                  public ConditionThread2(ConditionTest conditionTest) {
                      this.conditionTest = conditionTest;
                  }

                  @Override
                  public void run() {
                      if (!conditionTest.flag) {
                          conditionTest.task2();
                      }
                  }
              }

              public static void main(String[] args) throws InterruptedException {
                  ConditionTest conditionTest = new ConditionTest();
                  new ConditionThread1(conditionTest).start();
                  new ConditionThread2(conditionTest).start();
                  Thread.sleep(1000);
                  System.out.println("flag 改變。。。");
                  conditionTest.updateFlag();
              }
          }










          瀏覽 60
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  亚洲免费黄色 | 青娱乐99| 黄免费视频网站 | 国产美女内射视频 | 黄色录像毛片 |