Java并發編程Lock顯示鎖的了解

Lock是一個接口提供無條件的,可輪詢的 ,定時的,可中斷的鎖獲取操作,所有加鎖和解鎖的方法都是顯示的。

Lock接口方法

  public abstract void lock(); //獲取鎖

這個就是平常用的最多的方法,用來獲取鎖,如果沒有獲取到鎖則等待。不過為了避免產生死鎖,一般都要跟try{}finally{} 一起使用

  lock.lock(); //獲取鎖
        try {
            //業務處理
        }finally {
            lock.unlock(); //釋放鎖
        }
    }
 public abstract void unlock(); //釋放鎖

用來釋放鎖,這個沒什么好細說,用的時候,注意一定在finally包裹里使用,不然容易出現死鎖。

    public abstract void lockInterruptibly()throws InterruptedException; //獲取鎖

這個方法是也是獲取鎖,跟lock() 跟相似,獲取鎖,獲取不到,等待直到獲取到鎖為止。但是它是可以被中斷的,這個方法直接throws InterruptedException 就是為了讓調用者,自己去處理線程的中斷。這個方法強調的是線程在獲取鎖的時候可以被中斷,獲取到鎖的時候也可以被中斷,詳細看下面的例子。

 void method()throws InterruptedException{
try {
            //業務處理
        }finally {
            lock.unlock(); //釋放鎖
        }
}
public abstract boolean tryLock(); //獲取鎖,有返回值

這個方法與lock()主要的區別在,lock()方法獲取不到鎖,會等待,直到獲取到鎖為止。tryLock()只會獲取一次,并將結果返回,獲取到鎖返回true,反之false。代碼模板:

if(lock.tryLock()) {
            try {
            //上鎖的業務處理   
            }finally {
                lock.unlock(); //釋放鎖
            }
        }else {
            //獲取鎖失敗的業務處理
        }
  public void tryLock(long paramLong,TimeUnit paramTimeUnit) throws InterruptedException;

這個方法與tryLock()有點類似,在指定的時間內獲取鎖,如果沒有獲取到返回false,如果在指定的時間內,獲取到鎖則返回true。使用模板也與tryLock() 一樣。

  public abstract Condition newCondition();

返回用來與此Lock實例一起使用的Condition實例。

Lock實現ReentrantLock 使用

lock() 方法使用

public class LockDemo {
    
    private List<String> list = new ArrayList<>();
    private final ReentrantLock lock = new ReentrantLock();
    
    public static void main(String[] args) throws InterruptedException {
        final LockDemo l = new LockDemo();
        for(int i = 0; i < 5 ; i++) {
          new Thread(()->{l.insert(Thread.currentThread());}).start(); 
        }
        Thread.sleep(2000); //為了看到list的結果,誰兩秒鐘
        System.out.println("執行完成了");
        l.list.forEach(System.out::println);
        
    }
    
   public   void insert(Thread thread) {
        lock.lock();
        try {
        System.out.println("此線程已經獲取到鎖了 "+thread.getName());
        list.add(thread.getName());
        }finally {
            lock.unlock();
            System.out.println("此線程已經釋放鎖了 "+thread.getName());
        }
    }
   }

}

執行結果

此線程已經獲取到鎖了 Thread-1
此線程已經釋放鎖了 Thread-1
此線程已經獲取到鎖了 Thread-0
此線程已經釋放鎖了 Thread-0
此線程已經獲取到鎖了 Thread-3
此線程已經釋放鎖了 Thread-3
此線程已經獲取到鎖了 Thread-4
此線程已經釋放鎖了 Thread-4
此線程已經獲取到鎖了 Thread-2
此線程已經釋放鎖了 Thread-2
執行完成了
Thread-1
Thread-0
Thread-3
Thread-4
Thread-2

可以看出獲取鎖的順序跟list的順序是一樣。每個線程都是先獲取到鎖,釋放鎖在到下一個線程,不存在交叉的情況。

tryLock() 方法使用

public class LockDemo {
    private List<String> list = new ArrayList<>();
    private final ReentrantLock lock = new ReentrantLock();
    
    public static void main(String[] args) throws InterruptedException {
        final LockDemo l = new LockDemo();
        for(int i = 0; i < 5 ; i++) {
          new Thread(()->{l.tryInsert(Thread.currentThread());}).start(); 
        }
        Thread.sleep(2000);
        System.out.println("執行完成了");
        l.list.forEach(System.out::println);    
    }
   void tryInsert(Thread thread) {
       if(lock.tryLock()) {//tryLock()方法是有返回值的,它表示用來嘗試獲取鎖,如果獲取成功,則返回true,如果獲取失敗(
           System.out.println("此線程已經獲取到鎖了 "+thread.getName());                              //即鎖已被其他線程獲取),
           try {              //則返回false,也就說這個方法無論如何都會立即返回。在拿不到鎖時不會一直在那等待。 這個方法就是線程 去競爭鎖,獲取到執行 不然到else里面去
           list.add(thread.getName());
           }finally {
               lock.unlock();
               System.out.println("此線程已經釋放鎖了 "+thread.getName());
           }
       }else {
           System.out.println("此線程獲取鎖失敗 "+thread.getName());
       }
   }
}

執行的結果

此線程獲取鎖失敗 Thread-0
此線程獲取鎖失敗 Thread-3
此線程獲取鎖失敗 Thread-1
此線程獲取鎖失敗 Thread-2
此線程已經獲取到鎖了 Thread-4
此線程已經釋放鎖了 Thread-4
執行完成了
Thread-4

可以看出5個線程同時獲取鎖,只有一個線程成功的,其他的線程都進入else中。這個對應開頭說的可輪詢的,如果加上時間就是定時的。

lockInterruptibly()方法使用

public class LockDemo {

    private List<String> list = new ArrayList<>();
    private final ReentrantLock lock = new ReentrantLock();

    public static void main(String[] args) throws InterruptedException {
        final LockDemo l = new LockDemo();
        for (int i = 0; i < 5; i++) {
            Thread t = new Thread(() -> {
                l.interruptInsert(Thread.currentThread());
            });
            t.start();
            if (i % 2 == 0) {//對偶數進行中斷,為了不讓全部的線程都中斷,list沒有結果集
                Thread.sleep(10); //讓線程獲取去獲取鎖,在進行中斷
                t.interrupt(); // 直接執行中斷 
            }
        }
        Thread.sleep(5000);
        System.out.println("執行完成了");
        l.list.forEach(System.out::println);

    }

    void interruptInsert(Thread thread) {
        try {
            lock.lockInterruptibly();
            System.out.println("線程已經獲取到鎖了 : " + thread.getName());
            Thread.sleep(2000);
            list.add(thread.getName());
        } catch (InterruptedException e) {
            System.out.println("當前線程直接執行中斷: " + thread.getName());
            e.printStackTrace();
        } finally {
            lock.unlock(); // 釋放鎖
            System.out.println("此線程已經釋放鎖了 " + thread.getName());
        }
    }
}

![image.png](https://upload-images.jianshu.io/upload_images/9213940-21a3f18890d75f77.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

可以看出Thread-0,Thread-2 已經獲取到鎖了,還是被中斷,Thread-4在等待獲取鎖,直接被中斷的,終止等待。


          
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容