iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 14
0
Software Development

30 天介紹 Java 的 Thread系列 第 14

Day 14 介紹 ReentrantLock (一)

今天要介紹 java.util.concurrent.locks package 下面 ReentrantLock 的類別,它是屬於 Lock 的一種實作,其實 ReentrantLock 相似於前面幾天所提到的 Synchronized。它們之間主要的差別在於 ReentrantLock 有 Lock 和 Unlock 開發程式的人要自已的控制鎖, Synchronized 會自動的幫我們控制鎖。

ReentrantLock 類別主要提供了 lock()、unlock()、newCondition()、tryLock()…等等的方法,今天主要是介紹使用 lock 和 unlock 方法。

lock 方法主要是要把保護的變數鎖圯來,然後 unlock 方法主要是把鎖打開來,讓其它的執行緒去取得共享變數的存取。

以下吏用 ReentrantLock 類別,來保護 ArrayList 非執行緒安全的 Collection,使得多執行在同時 add 資料時不會有掉資料的問題,Sample code 如下:

import java.util.List;
import java.util.concurrent.locks.Lock;

public class LockThreadExample implements Runnable {
  private Lock lock;
  private List<String> list;

  public LockThreadExample(Lock lock, List<String> list) {
    this.lock = lock;
    this.list = list;
  }

  @Override
  public void run() {
    try {
      this.lock.lock();
      for (int i = 1; i <= 10; i++) {
        Thread.sleep(1000L);
        this.list.add("value-" + i);
      }
    } catch(Exception e) {
      throw new RuntimeException(e);
    } finally {
      this.lock.unlock();
    }
  }
}

以上是執行緒的程式,建構子主要會接收主程式傳入進來的 list 變數和 ReentrantLock 的 Lock 變數,當在執行 run 方法的時侯會先啟動 lock 鎖起來不讓其它的執行緒進來,等待執完畢之後才會把鎖 unlock 打開來。在這裡會放在 finally 區塊呼叫的原因主要是,預防當程式執行到一半如何出現 Exception 時,也要能夠 unlock 不然程式有可能就會發現問題。就類似我們在使用開檔或是建立 JDBC Connection 時關閉連線也會放在 finally 區塊裡。

以下是主程式的寫法:

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Test {
  public static void main(String args[]) throws Exception {
    Lock lock = new ReentrantLock();
    List<String> list = new ArrayList<String>();
    LockThreadExample a = new LockThreadExample(lock, list);

    Thread thread1 = new Thread(a);
    Thread thread2 = new Thread(a);
    Thread thread3 = new Thread(a);

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

    thread1.join();
    thread2.join();
    thread3.join();

    System.out.println(list.size());
  }
}

在主程式裡主要會建立 ArrayList 和 ReentrantLock 的物件,並且會啟動 3 個執行緒,以下是執行的結果:

30

從結果可以看到是預期的結果 3 個執行緒,每個執行緒執行 10 次迴圈 3*10=30,因此 ReentrantLock 可以保諏非執行安全的物件。

明天還會繼續介紹 ReentrantLock 的 newCondition() 的用法。


上一篇
Day 13 使用 Exchanger 寫 Producer Consumer 程式
下一篇
Day 15 介紹 ReentrantLock (二)
系列文
30 天介紹 Java 的 Thread30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
williamyeh
iT邦新手 5 級 ‧ 2018-12-05 16:51:44

『其實 ReentrantLock 相似於前面幾天所提到的 Synchronized。它們之間主要的差別在於 ReentrantLock 有 Lock 和 Unlock 開發程式的人要自已的控制鎖, Synchronized 會自動的幫我們控制鎖。』

其實主要差別不止如此。

  1. 歷史因素, ReentrantLock 是效率較高的。

  2. Lock granuality 不同。請見良葛格的文章: https://www.ithome.com.tw/voice/106958

我再去研究看看, 謝謝啦!

我要留言

立即登入留言