java拓展----Lock鎖
目錄
1.介紹Lock
2.Lock的基本使用
3.Lock之執行緒之間的通訊
4.總結
一、介紹Lock
首先先講一下筆者為什麼會涉及到Lock這個東西,使用synchronized來鎖物件或方法時,如果被鎖的這個方法發生阻塞(sleep),那麼將影響鎖資源的釋放,
而其他處於等待狀態的物件或方法將一直處於等待狀態,直到休眠完或阻塞清除,這就帶來了一大併發症。而使用Lock則可以解決這一問題。
Lock與synchronized之間有很多差異:
1.Lock是一個介面,synchronized則是java中的一個關鍵字
2.Lock需要手動釋放鎖,synchronized不需要手動釋放鎖
二、Lock的基本使用
Lock的API
Lock是一個介面,他需要由ReentrantLock、ReentrantReadWriteLock.ReadLock、ReentrantReadWriteLock.WriteLock來建立
它主要的方法有:
ReentrantWriteReadLock是讀寫鎖,它將檔案的讀和寫分開,在這不多做研究。
如想了解的讀者請參考https://blog.csdn.net/zhuhezan/article/details/6613108
以下是Lock的基本使用:
package com.demo.thread; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class LockThread { //建立鎖物件 Lock lock = new ReentrantLock(); public void lock(String name) { // 獲取鎖 lock.lock(); try { System.out.println(name+ "獲取鎖"); // 訪問此鎖保護的資源 } finally { // 釋放鎖 lock.unlock(); System.out.println(name + "釋放鎖"); } } public static void main(String[] args) { LockThread lt = new LockThread(); new Thread(() -> lt.lock("A")).start(); new Thread(() -> lt.lock("B")).start(); } }
三、Lock之執行緒之間的通訊
如果我們不使用Lock,要做到執行緒之間的通訊我們需要使用到Object類中的wait、notify、notifyAll方法來控制執行緒間的通訊。在jdk1.5當中,執行緒之間的通訊如果使用Lock介面的話需要使用到newCondition方法來建立需要通訊的物件Condition。
一下是newCondition方法的具體解釋:
Condition物件的方法如下:
一下是使用condition完成Lock物件執行緒間的通訊Demo:
package com.demo.condition; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * Condition初次使用 * 使用Condition控制執行緒間的通訊 * @author Administrator * */ public class ConditionDemo { public static void main(String[] args) { Output output = new Output(); for(int i =0;i<2;i++){ new Thread(new Runnable() { public void run() { output.get1(1); } }).start(); new Thread(new Runnable() { public void run() { output.get2(2); } }).start(); new Thread(new Runnable() { public void run() { output.get3(3); } }).start(); } } } class Output{ private int count =1; //建立Lock物件 final Lock lock = new ReentrantLock(); //建立三個condition物件 private Condition condition1 = lock.newCondition(); private Condition condition2 = lock.newCondition(); private Condition condition3 = lock.newCondition(); public void get1(int i){ //獲取鎖資源 lock.lock(); System.out.println("condition1已獲取鎖資源"); try { while(count!=1){ condition1.await(); } System.out.println("condition1獲取到資源"); for(int j=0;j<10;j++){ System.out.println(i+"正在執行condition1"+j); Thread.sleep(1000); } count++; //喚醒第二個等待的執行緒 condition2.signal(); } catch (InterruptedException e) { e.printStackTrace(); }finally{ //釋放鎖資源,避免鎖死狀態 lock.unlock(); } } public void get2(int i){ //獲取鎖資源 lock.lock(); System.out.println("condition2已獲取鎖資源"); try { while(count!=2){ condition2.await(); } System.out.println("condition2獲取到資源"); for(int j=0;j<10;j++){ System.out.println(i+"正在執行condition2"+j); Thread.sleep(1000); } count++; //喚醒第三個等待的執行緒 condition3.signal(); } catch (InterruptedException e) { e.printStackTrace(); }finally{ //釋放鎖資源,避免鎖死狀態 lock.unlock(); } } public void get3(int i){ //獲取鎖資源 lock.lock(); System.out.println("condition3已獲取鎖資源"); try { while(count!=3){ condition3.await(); } System.out.println("condition3獲取到資源"); for(int j=0;j<10;j++){ System.out.println(i+"正在執行condition3"+j); Thread.sleep(1000); } count=1; //喚醒第一個等待的執行緒 condition1.signal(); } catch (InterruptedException e) { e.printStackTrace(); }finally{ //釋放鎖資源,避免鎖死狀態 lock.unlock(); } } }
四、總結
結合以上觀點來看,總而言之,使用Lock相對於傳統使用synchronized關鍵字來說,邏輯更清晰,避免了執行緒等待的併發症。而且
我們還可以直觀的觀測到執行緒之間或去鎖的狀態。個人還是推薦是用Lock代替synchronized的。