Lock接口簡介


在Java多線程編程中,我們經常使用synchronized關鍵字來實現同步,控制多線程對變量的訪問,來避免並發問題。

但是有的時候,synchronized關鍵字會顯得過於沉重,不夠靈活。synchronized 方法或語句的使用提供了對與每個對象相關的隱式監視器鎖的訪問,但卻強制所有鎖獲取和釋放均要出現在一個塊結構中:當獲取了多個鎖時,它們必須以相反的順序釋放,且必須在與所有鎖被獲取時相同的詞法范圍內釋放所有鎖。

這個時候Lock出現。

Lock不是Java中的關鍵字而是 java.util.concurrent.locks 包中的一個接口。下面我們簡單介紹一下Lock接口。

 

一、Lock接口簡介

Lock 實現提供了比使用 synchronized 方法和語句可獲得的更廣泛的鎖定操作。此實現允許更靈活的結構,可以具有差別很大的屬性,可以支持多個相關的 Condition 對象。

Lock相對於synchronized關鍵字而言更加靈活,你可以自由得選擇我你想要加鎖的地方。當然更高的自由度也帶來更多的責任。

我們通常會在try...catch模塊中使用lock關鍵字,在finally模塊中釋放鎖。下面是示范代碼。

    Lock l = ...; l.lock(); try { // access the resource protected by this lock
     } finally { l.unlock(); }

鎖的鎖定和釋放如果在不同的模塊時,需要謹慎編碼,確保最后鎖一定能夠得到釋放。

 

二、Lock接口中定義的方法

1、void lock()
獲取鎖。如果鎖不可用,出於線程調度目的,將禁用當前線程,並且在獲得鎖之前,該線程將一直處於休眠狀態

2、void lockInterruptibly()
如果當前線程未被中斷,則獲取鎖。

3、Condition newCondition()
返回綁定到此 Lock 實例的新 Condition 實例。

4、boolean tryLock()
僅在調用時鎖為空閑狀態才獲取該鎖。如果鎖可用,則獲取鎖,並立即返回值 true。如果鎖不可用,則此方法將立即返回值 false

5、boolean tryLock(long time, TimeUnit unit)
如果鎖在給定的等待時間內空閑,並且當前線程未被中斷,則獲取鎖。

6、void unlock()
釋放鎖。在等待條件前,鎖必須由當前線程保持。調用 Condition.await() 將在等待前以原子方式釋放鎖,並在等待返回前重新獲取鎖。

 

三、實現類ReentrantLock

Lock接口有三個實現類分別是ReentrantLock, ReentrantReadWriteLock.ReadLock, ReentrantReadWriteLock.WriteLock。后面兩個是內部類。

第一個ReentrantLock,在我們平常使用中更為頻繁。

ReentrantLock是一個可重入的互斥鎖 Lock,它具有與使用 synchronized 方法和語句所訪問的隱式監視器鎖相同的一些基本行為和語義,但功能更強大。

ReentrantLock的構造方法接受一個可選的公平 參數。當設置為 true 時,在多個線程的爭用下,這些鎖傾向於將訪問權授予等待時間最長的線程。否則此鎖將無法保證任何特定訪問順序。也就是說這里可以設置鎖的類型為公平鎖還是非公平鎖。但是,需要注意的是公平鎖的情況下,也不能完全確保公平,它總是趨向公平的情況。

ReentrantLock類中還定義了Lock接口之外的方法,例如int getHoldCount() 、boolean hasQueuedThreads() 、boolean hasWaiters(Condition condition)等等,這些方法可以查詢當前鎖的狀態。

 

四、代碼使用

package com.test;

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

public class TestLock {
    
    public static void main(String[] args) {
        Lock lock = new ReentrantLock();
        for(int i=0;i<5;i++){
            ThreadPrintStar threadPrintStar = new TestLock().new ThreadPrintStar(lock);
            threadPrintStar.start();
        }                
    }
    
    /**
     * 打印星星
     * @author LKB
     *
     */
    class ThreadPrintStar extends Thread{
        private Lock lock;
        
        public ThreadPrintStar(Lock lock) {
            // TODO Auto-generated constructor stub
            this.lock = lock;
        }
        
        public void run(){
            lock.lock();
            try {    
                for(int i=0;i<5;i++){
                    if(i%2 == 0)
                        System.out.println("i = " + i + "+++" + Thread.currentThread().getName() +
                                " print: " + "☆☆");
                    else 
                        System.out.println("i = " + i + "+++" + Thread.currentThread().getName() +
                                " print: " + "★★");
                                            
                }
                System.out.println();
                System.out.println();
            } catch (Exception e) {
                // TODO: handle exception
                e.printStackTrace();
            }finally {
                lock.unlock();
            }
        }
    }
    
}

下面是程序運行結果,可以看到我們通過Lock實現了同步。

 

i = 0+++Thread-0 print: ☆☆
i = 1+++Thread-0 print: ★★
i = 2+++Thread-0 print: ☆☆
i = 3+++Thread-0 print: ★★
i = 4+++Thread-0 print: ☆☆


i = 0+++Thread-1 print: ☆☆
i = 1+++Thread-1 print: ★★
i = 2+++Thread-1 print: ☆☆
i = 3+++Thread-1 print: ★★
i = 4+++Thread-1 print: ☆☆


i = 0+++Thread-2 print: ☆☆
i = 1+++Thread-2 print: ★★
i = 2+++Thread-2 print: ☆☆
i = 3+++Thread-2 print: ★★
i = 4+++Thread-2 print: ☆☆


i = 0+++Thread-4 print: ☆☆
i = 1+++Thread-4 print: ★★
i = 2+++Thread-4 print: ☆☆
i = 3+++Thread-4 print: ★★
i = 4+++Thread-4 print: ☆☆


i = 0+++Thread-3 print: ☆☆
i = 1+++Thread-3 print: ★★
i = 2+++Thread-3 print: ☆☆
i = 3+++Thread-3 print: ★★
i = 4+++Thread-3 print: ☆☆

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM