首頁 > Java > java教程 > Java中的鎖是什麼? Java中鎖的詳細介紹

Java中的鎖是什麼? Java中鎖的詳細介紹

不言
發布: 2018-09-27 17:16:34
原創
10379 人瀏覽過

本篇文章帶給大家的內容是關於Java中的鎖是什麼? Java中鎖的詳細介紹,有一定的參考價值,有需要的朋友可以參考一下,希望對你有幫助。

1.簡介

#JAVA中實作加鎖是透過Synchronized關鍵字以及 java.util.concurrent套件下的相關類別。

Java提供的實作加鎖的相關API:

Java中的鎖是什麼? Java中鎖的詳細介紹

Lock提供了比使用Synchronized同步方法和同步語句區塊更廣泛的鎖定操作。

2.java.util.concurrent套件

Lock介面

//试图获取锁.
void lock() 
 
//如果当前线程未被中断,则获取锁.
void lockInterruptibly()
         
//返回绑定到此 Lock 实例的新 Condition 实例.
Condition newCondition()
          
//仅在调用时锁为空闲状态才获取该锁.
boolean tryLock()
          
//如果锁在给定的等待时间内空闲,并且当前线程未被中断,则获取锁.
boolean tryLock(long time, TimeUnit unit)
          
//试图释放锁.
void unlock()
登入後複製

ReentranLock類別

#建構方法

//创建一个 ReentrantLock 的实例.
ReentrantLock()          
//创建一个具有给定公平策略的 ReentrantLock实例.
ReentrantLock(boolean fair)
登入後複製

公平鎖定:多執行緒依照申請鎖定的順序取得鎖定。

非公平鎖定:多執行緒並非依照申請鎖的順序取得鎖,也就是先申請鎖的執行緒不一定第一個能取得鎖。

常用方法摘要

//试图获取锁.   void lock() //如果当前线程未被中断,则获取锁.void lockInterruptibly() //仅在调用时锁未被另一个线程保持的情况下,才获取该锁.boolean tryLock() //如果锁在给定等待时间内没有被另一个线程保持,且当前线程未被中断,则获取该锁.  boolean tryLock(long timeout, TimeUnit unit) //试图释放此锁.    void unlock() //返回用来与此 Lock 实例一起使用的 Condition 实例.Condition newCondition() //如果此锁的公平设置为 true,则返回 true.boolean isFair() //返回正等待获取此锁的线程估计数.int getQueueLength()     //返回等待与此锁相关的给定条件的线程估计数.int getWaitQueueLength(Condition condition) //返回标识此锁及其锁定状态的字符串.String  toString()
登入後複製

Condition介面

//使当前线程在接收到信号前或被中断前一直保持等待状态.
void await()
          
//使当前线程在接收到信号前或被中断前或达到指定时间前一直保持等待状态(TimeUnit为时间单位).
boolean await(long time, TimeUnit unit)
          
//使当前线程在接收到信号前或被中断前或达到指定时间前一直保持等待状态(单位为毫秒).
long awaitNanos(long nanosTimeout)
 
//使当前线程在接收到信号前或被中断前或达到最后日期期限前一直保持等待状态.
boolean awaitUntil(Date deadline)
 
//唤醒一个在该Condition实例等待的线程.
void signal()
 
//唤醒所有在该Condition实例等待的线程.         
void signalAll()
登入後複製

一個Condition實例將與一個Lock實例進行綁定,作為該Lock實例的條件控制。

 Condition介面宣告的方法呼叫前都需要先取得與此Condition相關的鎖定。

 await()、await(long time, TimeUnit unit)、awaitNanos(long nanosTimeout)、awaitUntil(Date deadline)這些方法呼叫後,則與此Condition相關的鎖將以原子方式釋放。

 signal()、signalAll()方法呼叫後,被喚醒的執行緒需要重新取得鎖定才能從await()方法進行傳回。

使用範例:

/**
* @Auther: ZHUANGHAOTANG
* @Date: 2018/9/26 17:36
* @Description:
*/
public class TestReentranLock implements Runnable{

    /**
     * 可重入锁
     */
    private ReentrantLock reentrantLock = new ReentrantLock(true);

    /**
     * 锁条件
     */
    private Condition condition = reentrantLock.newCondition();

    /**
     * 业务处理
     */
    public void service(){
        String threadName = Thread.currentThread().getName();
        System.out.println(threadName+":尝试获取锁");
        reentrantLock.lock();
        System.out.println(threadName+":获取锁成功");
        try {
            System.out.println(threadName+":使当前线程等待,并释放锁资源。");
            condition.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            reentrantLock.unlock();
            System.out.println(threadName+":释放锁");
        }
    }

    /**
     * 唤醒在该Condition实例等待的线程
     */
    public void signalAll(){
        reentrantLock.lock();
        condition.signalAll();
        reentrantLock.unlock();
    }

    @Override
    public void run() {
        service();
    }

    public static void main(String[] args) {

        TestReentranLock testReentranLock = new TestReentranLock();

        Thread threadA = new Thread(testReentranLock,"线程A");
        Thread threadB = new Thread(testReentranLock,"线程B");
        Thread threadC = new Thread(testReentranLock,"线程C");

        threadA.start();
        threadB.start();
        threadC.start();

        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        testReentranLock.signalAll();

    }

}
登入後複製

##公平鎖定執行結果:

线程B:尝试获取锁
线程A:尝试获取锁
线程B:获取锁成功
线程C:尝试获取锁
线程B:使当前线程等待,并释放锁资源。
线程A:获取锁成功
线程A:使当前线程等待,并释放锁资源。
线程C:获取锁成功
线程C:使当前线程等待,并释放锁资源。
线程B:释放锁
线程C:释放锁
线程A:释放锁
登入後複製

非公平鎖定執行結果:

线程B:尝试获取锁
线程A:尝试获取锁
线程A:获取锁成功
线程C:尝试获取锁
线程A:使当前线程等待,并释放锁资源。
线程C:获取锁成功
线程C:使当前线程等待,并释放锁资源。
线程B:获取锁成功
线程B:使当前线程等待,并释放锁资源。
线程A:释放锁
线程B:释放锁
线程C:释放锁
登入後複製

ReadWriteLock介面

//返回用于读取操作的锁.
Lock readLock()          
//返回用于写入操作的锁.
Lock writeLock()
登入後複製

ReentrantReadWriteLock類別

建構方法

//创建一个ReentrantReadWriteLock实例.
ReentrantReadWriteLock()        
//创建一个具有给定公平策略的ReentrantReadWriteLock实例.
ReentrantReadWriteLock(boolean fair)
登入後複製

##常用方法摘要#

//返回用于读取操作的锁.
Lock ReentrantReadWriteLock。ReadLock。readLock()   
//返回用于写入操作的锁.
Lock ReentrantReadWriteLock。WriteLock。writeLock()
//返回等待获取读取或写入锁的线程估计数目.
int getQueueLength()
//如果此锁的公平设置为 true,则返回 true.
boolean isFair()
//返回标识此锁及其锁状态的字符串.
String toString()
登入後複製

ReadLock/WriteLock靜態內部類別

常用方法摘要

//试图获取锁.
void lock() 
//如果当前线程未被中断,则获取锁.
void lockInterruptibly()
          
//返回绑定到此 Lock 实例的新 Condition 实例.
Condition newCondition()
          
//仅在调用时锁为空闲状态才获取该锁.
boolean tryLock()
          
//如果锁在给定的等待时间内空闲,并且当前线程未被中断,则获取锁.
boolean tryLock(long time, TimeUnit unit)
          
//试图释放锁.
void unlock()
 
//返回标识此锁及其锁状态的字符串.
String toString()
登入後複製

因為ReadLock不支援條件,因此當呼叫了ReadLock的newCondition()方法時將會拋出UnsupportedOperationException異常。

使用ReentrantReadWriteLock的讀鎖以及寫鎖,將會遵循讀讀共享、寫寫互斥、讀寫互斥。

使用範例:

/**
* @Auther: ZHUANGHAOTANG
* @Date: 2018/9/26 18:04
* @Description:
*/
public class TestReentrantReadWriteLock implements Runnable{


    private ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock(true);

    /**
     * 读锁
     */
    private Lock readLock = reentrantReadWriteLock.readLock();

    /**
     * 写锁
     */
    private Lock writeLock = reentrantReadWriteLock.writeLock();

    /**
     * 读取操作
     */
    public void reading(){
        String threadName = Thread.currentThread().getName();
        System.out.println(threadName+":尝试获取读锁");
        readLock.lock();
        System.out.println(threadName+":获取读锁成功");
        System.out.println(threadName+":释放读锁");
        readLock.unlock();
    }

    /**
     * 写入操作
     */
    public void writing(){
        String threadName = Thread.currentThread().getName();
        System.out.println(threadName+":尝试获取写锁");
        writeLock.lock();
        System.out.println(threadName+":获取写锁成功");
        System.out.println(threadName+":释放写锁");
        writeLock.unlock();
    }


    public static void main(String[] args) {
        TestReentrantReadWriteLock testReentrantReadWriteLock = new TestReentrantReadWriteLock();

        Thread threadA = new Thread(testReentrantReadWriteLock,"线程A");
        Thread threadB = new Thread(testReentrantReadWriteLock,"线程B");
        Thread threadC = new Thread(testReentrantReadWriteLock,"线程C");

        threadA.start();
        threadB.start();
        threadC.start();
    }

}
登入後複製

讀取讀取共享執行結果:

@Overridepublic void run() {     
 //读读共享      
 reading();
}
登入後複製
线程A:尝试获取读锁
线程B:尝试获取读锁
线程A:获取读锁成功
线程A:释放读锁
线程C:尝试获取读锁
线程C:获取读锁成功
线程C:释放读锁
线程B:获取读锁成功
线程B:释放读锁
登入後複製

讀鎖能被多個執行緒同時獲取,能提高讀取的效率(雖然只用讀鎖時可以不進行釋放,但會影響寫鎖的獲取)

寫寫互斥執行結果:#

@Overridepublic void run() {  
    //写写互斥     
    writing();
}
登入後複製
线程A:尝试获取写锁
线程B:尝试获取写锁
线程A:获取写锁成功
线程C:尝试获取写锁
线程A:释放写锁
线程B:获取写锁成功
线程B:释放写锁
线程C:获取写锁成功
线程C:释放写锁
登入後複製

寫鎖定同一時刻只能被一個線程獲取。

讀寫互斥執行結果:#

@Overridepublic void run() {      
   //读写互斥      
   writing();
  reading();
}
登入後複製
线程A:尝试获取写锁
线程C:尝试获取写锁
线程B:尝试获取写锁
线程A:获取写锁成功
线程A:释放写锁
线程A:尝试获取读锁
线程C:获取写锁成功
线程C:释放写锁
线程C:尝试获取读锁
线程B:获取写锁成功
线程B:释放写锁
线程B:尝试获取读锁
线程C:获取读锁成功
线程C:释放读锁
线程A:获取读锁成功
线程A:释放读锁
线程B:获取读锁成功
线程B:释放读锁
登入後複製

讀的時候不能寫,寫的時候不能讀,即獲取讀鎖時如果寫鎖此時被線程持有則將等待寫鎖被釋放,獲取寫鎖時如果讀鎖此時有被線程持有則將等待讀鎖被釋放且寫鎖未被持有。

3.Java中鎖定的分類

Java中的鎖定是依照鎖定的特性來進行劃分的。

公平鎖定/非公平鎖定

公平鎖定:多執行緒依照申請鎖定的順序取得鎖。

非公平鎖定:多執行緒並非依照申請鎖的順序取得鎖,也就是並未第一個lock()的執行緒能第一個取得鎖定。

對於ReentranLock以及ReentrantReadWriteLock鎖定其可以透過建構方法來設定是公平鎖定還是非公平鎖定。

對於Synchronized關鍵字其屬於非公平鎖定。

共享鎖定/獨享鎖定

共享鎖定:指該鎖定能被多個執行緒同時持有,對於ReadLock其屬於共享鎖。

獨享鎖:指該鎖同一時刻只能由一個執行緒持有,對於ReentranLock、WriteLock、Synchronized其屬於獨享鎖。

樂觀鎖定/悲觀鎖定

樂觀鎖定和悲觀鎖定並不是具體的鎖特性,而是看待並發時的角度。

樂觀鎖定:認為並發操作不會影響資料的完整性,因此無需進行加鎖。

悲觀鎖定:認為並發操作一定會影響資料的完整性,因此必須進行加鎖。

讀取操作適用於樂觀鎖,即不進行加鎖,能夠提升讀取資料的效率。

#寫入運算適用於悲觀鎖,也就是一定要進行加鎖。

分段鎖定

分段鎖定是指鎖定的設計,透過細化鎖定的粒度來控制並發的操作,Java的ConcurrentHashMap中的segment就是透過分段鎖定的設計來實現並發操作。

偏向鎖定/輕量級鎖定/重量級鎖定

#偏向鎖定、輕量級鎖定、重量級鎖定都是指鎖的不同狀態而且是針對Synchronized關鍵字而言的。

偏向鎖定:指同步方法或同步語句區塊一直只被一個執行緒所持有,則此時鎖的狀態為偏向鎖,會降低該執行緒取得鎖的成本。

輕量級鎖:當鎖的狀態為偏向鎖,若被其他執行緒訪問,則此時其他執行緒將以自旋的方式嘗試取得鎖,則此時鎖的狀態為輕量級鎖。

自旋即是透過循環一定次數的方式來嘗試取得鎖,使用此方式不會阻塞線程,缺點是消耗CPU的效能。

重量級鎖:當鎖的狀態是輕量級鎖,若其他執行緒自旋過後仍未取得鎖,則此時鎖的狀態為重量級鎖,此時其他執行緒將會進入阻塞狀態,效能降低。

當鎖的狀態為偏向鎖定時效能最高,重量級鎖定時效能最低。

以上是Java中的鎖是什麼? Java中鎖的詳細介紹的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
作者最新文章
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板