java 併發編程 ReentrantLock

本文參考自大佬 公衆號:路人甲java
添加鏈接描述

synchronized 的侷限性
synchronized是java內置的關鍵字,它提供了一種獨佔的加鎖方式。synchronized的獲取和釋放鎖由jvm實現,用戶不需要顯示的釋放鎖
如果當前線程獲取不到鎖,那麼會一直阻塞,其他線程也需要一直等待鎖的釋放。除非當前線程執行完成,或者結束阻塞,或者拋出異常,才能釋放鎖,別的線程纔可以繼續爭取鎖

ReentrantLock是Lock的默認實現,在聊ReentranLock之前,我們需要先弄清楚一些概念:

可重入鎖:可重入鎖是指同一個線程可以多次獲得同一把鎖;ReentrantLock和關鍵字Synchronized都是可重入鎖

可中斷鎖:可中斷鎖時只線程在獲取鎖的過程中,是否可以相應線程中斷操作。synchronized是不可中斷的,ReentrantLock是可中斷的

公平鎖和非公平鎖:公平鎖是指多個線程嘗試獲取同一把鎖的時候,獲取鎖的順序按照線程到達的先後順序獲取,而不是隨機插隊的方式獲取。synchronized是非公平鎖,而ReentrantLock是兩種都可以實現,不過默認是非公平鎖

t
ReentrantLock的基本使用(上鎖,保證數據安全)

package juc;

import java.util.concurrent.locks.ReentrantLock;

/**
 * @author yanjun.liu
 * @date 2020/6/29--19:31
 */
public class MyReentrantLock {
  private static   ReentrantLock lock=new ReentrantLock();

    private static Integer num=0;

    public static void add(){
        //對於共享變量的操作,需要保證原子性,上鎖
        lock.lock();
        try {
            for(int i=0;i<100000;i++){
                num++;
            }
        }finally {
            //解鎖
           lock.unlock();
        }

    }

    public static class T extends Thread{
        @Override
        public void run(){
            add();
        }
    }
    public static void main(String[] args) throws Exception{
        T t = new T();
        T t2 = new T();
        T t3 = new T();
        t.start();
        t2.start();
        t3.start();
        //main線程進行等待三條線程執行完成,在執行
        t.join();
        t2.join();
        t3.join();

        System.out.println(num);
    }
}

ReentrantLock的使用過程
創建鎖對象 private static ReentrantLock lock=new ReentrantLock();
上鎖 lock.lock()
解鎖 lock.unlock() 解鎖一定要放在finally中,否則發生異常無法釋放鎖,永久阻塞。。。。。

可重入鎖,同一個線程可以多次獲取同一把鎖,獲幾次,解幾次

改造上面的代碼,加鎖兩次

package juc;

import java.util.concurrent.locks.ReentrantLock;

/**
 * @author yanjun.liu
 * @date 2020/6/29--19:31
 */
public class MyReentrantLock {
  private static   ReentrantLock lock=new ReentrantLock();

    private static Integer num=0;

    public static void add(){
        //對於共享變量的操作,需要保證原子性,上鎖
        lock.lock();
        lock.lock();
        try {
            for(int i=0;i<100000;i++){
                num++;
            }
        }finally {
            //解鎖
            lock.unlock();
            lock.unlock();
        }

    }

    public static class T extends Thread{
        @Override
        public void run(){
            add();
        }
    }
    public static void main(String[] args) throws Exception{
        T t = new T();
        T t2 = new T();
        T t3 = new T();
        t.start();
        t2.start();
        t3.start();
        //main線程進行等待三條線程執行完成,在執行
        t.join();
        t2.join();
        t3.join();

        System.out.println(num);
    }
}

上鎖lock.lock();一定要放在try{}代碼塊之外,如果在try中上鎖,在上鎖之前,其他代碼拋出異常,那麼就會上鎖失敗,走finally釋放鎖就會拋出異常,因爲壓根就沒上鎖成功

package juc;

import java.util.concurrent.locks.ReentrantLock;

/**
 * @author yanjun.liu
 * @date 2020/6/29--19:31
 */
public class MyReentrantLock {
  private static   ReentrantLock lock=new ReentrantLock();

    private static Integer num=0;

    public static void add(){
        try {
            //這裏會拋出異常,下面上鎖代碼不會執行
            int x=1;
            x=1/0;
            lock.lock();
            lock.lock();
            for(int i=0;i<100000;i++){
                num++;
            }
        }finally {
            //解鎖會拋出異常
            lock.unlock();
            lock.unlock();
        }

    }

    public static class T extends Thread{
        @Override
        public void run(){
            add();
        }
    }
    public static void main(String[] args) throws Exception{
        T t = new T();
        T t2 = new T();
        T t3 = new T();
        t.start();
        t2.start();
        t3.start();
        //main線程進行等待三條線程執行完成,在執行
        t.join();
        t2.join();
        t3.join();

        System.out.println(num);
    }
}

上述代碼將拋出IllegalMonitorStateException異常

拋出該異常表明某一線程已經試圖等待對象的監視器,或者試圖通知其他正在等待對象的監視器,然而本身沒有指定的監視器的線程。
Exception in thread "Thread-0" Exception in thread "Thread-1" Exception in thread "Thread-2" java.lang.IllegalMonitorStateException
	at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(ReentrantLock.java:151)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(AbstractQueuedSynchronizer.java:1261)
	at java.util.concurrent.locks.ReentrantLock.unlock(ReentrantLock.java:457)
	at juc.MyReentrantLock.add(MyReentrantLock.java:26)
	at juc.MyReentrantLock$T.run(MyReentrantLock.java:35)
java.lang.IllegalMonitorStateException
	at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(ReentrantLock.java:151)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(AbstractQueuedSynchronizer.java:1261)
	at java.util.concurrent.locks.ReentrantLock.unlock(ReentrantLock.java:457)
	at juc.MyReentrantLock.add(MyReentrantLock.java:26)
	at juc.MyReentrantLock$T.run(MyReentrantLock.java:35)
java.lang.IllegalMonitorStateException
	at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(ReentrantLock.java:151)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(AbstractQueuedSynchronizer.java:1261)
	at java.util.concurrent.locks.ReentrantLock.unlock(ReentrantLock.java:457)
	at juc.MyReentrantLock.add(MyReentrantLock.java:26)
	at juc.MyReentrantLock$T.run(MyReentrantLock.java:35)
0
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章