首頁  >  文章  >  Java  >  Java並發關於重入鎖與讀寫鎖的詳解

Java並發關於重入鎖與讀寫鎖的詳解

黄舟
黄舟原創
2017-09-26 09:50:061646瀏覽

這篇文章主要介紹了Java並發編程之重入鎖與讀寫鎖,文中相關實例代碼詳細,測試可用,具有一定參考價值,需要的朋友可以了解下。

重入鎖定

重入鎖,顧名思義,就是支援重進入的鎖,它表示該鎖定能夠支援一個執行緒對資源的重複加鎖。重進入是指任意執行緒在取得到鎖定之後能夠再次取得該鎖定而不會被鎖定阻塞,該特性的實作需要解決以下兩個問題。

1、執行緒再次取得鎖定。鎖需要去識別獲取鎖的線程是否為當前佔據鎖的線程,如果是,則再次成功獲取。

2、鎖的最終釋放。線程重複n次獲取了鎖,隨後在第n次釋放該鎖後,其他線程能夠獲取到該鎖。鎖的最終釋放要求鎖定對於獲取進行計數自增,計數表示當前鎖被重複獲取的次數,而鎖被釋放時,計數自減,當計數等於0時表示鎖已經成功釋放。

Java內內建鎖定(synchronize)和Lock(ReentrantLock)都是可重入的

synchronized 實例


package com.home;
public class SynchronizedTest implements Runnable {
  public synchronized void method1() {
    System.out.println("method1获得锁,正常运行!");
    method2();
  }
  public synchronized void method2() {
    System.out.println("method2获得锁,也正常运行!");
  }
  @Override
  public void run() {
    method1();
  }
  public static void main(String[] args) {
    SynchronizedTest st = new SynchronizedTest();
    new Thread(st).start();
    new Thread(st).start();
  }
}

Lock 實例


#
package com.home;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LockTest implements Runnable {
  Lock lock = new ReentrantLock();
  public void method1() {
    lock.lock();
    System.out.println("method1获得锁,正常运行!");
    method2();
    lock.unlock();
  }
  public void method2() {
    lock.lock();
    System.out.println("method2获得锁,也正常运行!");
    lock.unlock();
  }
  @Override
  public void run() {
    method1();
  }
  public static void main(String[] args) {
    LockTest lt = new LockTest();
    new Thread(lt).start();
    new Thread(lt).start();
  }
}

兩個範例最後的結果都是正確的,結果如下:


method1获得锁,正常运行!
method2获得锁,也正常运行!
method1获得锁,正常运行!
method2获得锁,也正常运行!

可重入鎖定最大的功能是避免死鎖

讀取寫入鎖定

讀寫鎖維護了一對相關的鎖,一個用於只讀操作,一個用於寫入操作。只要沒有writer,讀取鎖可以由多個reader執行緒同時保持。寫入鎖是獨佔的。

可重入讀寫鎖定ReentrantReadWriteLock

ReentrantReadWriteLock物件提供了readLock()和writeLock()方法, 用於取得讀取鎖定和寫入鎖定.

讀取鎖定允許多個reader執行緒同時持有, 而寫入鎖定最多只能有一個writter執行緒持有.

##讀寫鎖的使用場合: 讀取共享資料的頻率遠大於修改共享資料的頻率. 在上述場合下, 使用讀寫鎖定控制共享資源的存取, 可以提高並發性能.


如果一個線程已經持有了寫入鎖, 則可以再持有讀寫鎖. 相反, 如果一個線程已經持有了讀取鎖, 則在釋放該讀取鎖之前, 不能再持有寫入鎖.


可以呼叫寫入鎖的newCondition()方法取得與該寫入鎖綁定的Condition物件, 此時與普通的互斥鎖並沒有什麼區別. 但是呼叫讀取鎖的newCondition ()方法將拋出異常.


範例


package com.home;
import java.util.Random;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
class ReadWrte {
  // 共享数据,可以多个线程读数据,只能有一个线程写数据
  private int data;
  // 创建读写锁
  ReadWriteLock rwLock = new ReentrantReadWriteLock();
  /**
   * 读数据,上读锁
   */
  public void get() {
    // 读锁
    rwLock.readLock().lock();
    try {
      System.out.println(Thread.currentThread().getName() + ",Read!");
      Thread.sleep((long) Math.random() * 1000);
      System.out.println(Thread.currentThread().getName() + " 读出的数据为:" +
        this.getData());
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      rwLock.readLock().unlock();
    }
  }
  /**
   * 写数据,上写锁
   *
   * @param data
   */
  public void put(int data) {
    // 写锁
    rwLock.writeLock().lock();
    try {
      System.out.println(Thread.currentThread().getName() + ",Write!");
      Thread.sleep((long) Math.random() * 1000);
      this.setData(data);
      System.out.println(Thread.currentThread().getName() + " 写入的数据为:" +
        this.getData());
    } catch (InterruptedException e) {
      e.printStackTrace();
    } finally {
      rwLock.writeLock().unlock();
    }
  }
  public int getData() {
    return data;
  }
  public void setData(int data) {
    this.data = data;
  }
}
/**
 * 测试类
 *
 * @author itmyhome
 *
 */
public class ReadWriteLockTest {
  /**
   * @param args
   */
  public static void main(String[] args) {
    // 创建ReadWrte对象
    final ReadWrte rw = new ReadWrte();
    for (int i = 0; i < 10; i++) {
      // 创建并启动10个读线程
      new Thread(new Runnable() {
          @Override
          public void run() {
            rw.get();
          }
        }).start();
      // 创建并启动10个写线程
      new Thread(new Runnable() {
          @Override
          public void run() {
            // 写入一个随机数
            rw.put(new Random().nextInt(8));
          }
        }).start();
    }
  }
}

輸出為


Thread-0,Read!
Thread-4,Read!
Thread-8,Read!
Thread-12,Read!
Thread-0 读出的数据为:0
Thread-4 读出的数据为:0
Thread-8 读出的数据为:0
Thread-12 读出的数据为:0
Thread-19,Write!
Thread-19 写入的数据为:5
Thread-7,Write!
Thread-7 写入的数据为:7
Thread-3,Write!
Thread-3 写入的数据为:4
Thread-16,Read!
Thread-16 读出的数据为:4
Thread-11,Write!
Thread-11 写入的数据为:0
Thread-15,Write!
Thread-15 写入的数据为:5
Thread-2,Read!
Thread-2 读出的数据为:5
Thread-17,Write!
Thread-17 写入的数据为:2
Thread-6,Read!
Thread-6 读出的数据为:2
Thread-1,Write!
Thread-1 写入的数据为:5
Thread-13,Write!
Thread-13 写入的数据为:4
Thread-9,Write!
Thread-9 写入的数据为:7
Thread-5,Write!
Thread-5 写入的数据为:2
Thread-10,Read!
Thread-10 读出的数据为:2
Thread-18,Read!
Thread-14,Read!
Thread-18 读出的数据为:2
Thread-14 读出的数据为:2

從圖中我們可以看出,可以多個執行緒同時讀,但只能一個執行緒寫,即寫資料和寫入資料一併完成。

總結#

以上是Java並發關於重入鎖與讀寫鎖的詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn