1. 程式人生 > >java拓展----Lock鎖

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的。