Java併發編程十 重入鎖ReentrantLock 讀寫鎖ReentrantReadWriteLock

Java併發編程十 重入鎖ReentrantLock 讀寫鎖ReentrantReadWriteLock

Java的concurrent併發包提供了一套與Synchronized關鍵字相同功能Lock,還有與wait()/notify()相同功能的Condition。

Lock的功能比傳統的Synchronized更加靈活。它具有嗅探鎖定和多路分支等功能(一個lock對象可以創建多個Condition)。

1.Lock和synchronized的區別和各自的特點

1、類型不同
Lock是一個接口,是JDK層面的實現;synchronized是Java的關鍵字,是JVM層面的實現,是Java的內置特性;這也造成了在鎖管理上的不同。
2、釋放鎖的方式
Lock是在編碼中進行鎖的操作,需要主動調用接口中的方法釋放鎖,所以使用Lock時需要配合try模塊,在finally中釋放鎖,不然一旦發生異常很可能造成死鎖現象;synchronized由於是JVM層面的實現,獲取鎖和釋放鎖的操作是不可見的,當發生異常時,鎖的釋放由JVM實現。
3、獲取鎖的過程
Lock接口中提供的方法,讓獲取鎖的過程更加靈活,編程人員可以方便的在獲取鎖的過程中進行多種操作,比如嘗試獲取鎖、設置獲取鎖的超時時間、中斷等待獲取鎖的線程等,應該說讓鎖的操作變得“豐富多彩”起來;synchronized是無法這麼靈活的對鎖進行操作的。
4、效率
基於讀寫鎖接口的擴展,Lock可以提高多個線程進行讀操作的效率,在大併發量的情況下,效率的提高會尤其明顯。

2.ReentrantLock

ReentrantLock 重入鎖 它與Synchronized關鍵字的功能相同只是需要自己手動釋放鎖,而線程間的通信機制wait()/notify()也有相應的代替實現Condition。其原理和Synchronized是一樣的。

/**
 * Created by lyyz on 18-5-17.
 */
public class ReentrantLock_eg {

    ReentrantLock reentrantLock = new ReentrantLock();
    Condition condition1 = reentrantLock.newCondition();
    Condition condition2 = reentrantLock.newCondition();


    public void method1(){
        try {
            reentrantLock.lock();
            System.out.println(Thread.currentThread().getName()+"進入mehtod1");
            System.out.println(Thread.currentThread().getName()+"condition1  休眠");
            condition1.await();
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName()+"完成mehtod1");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            reentrantLock.unlock();
        }
    }

    public void method2(){
        try {
            reentrantLock.lock();
            System.out.println(Thread.currentThread().getName()+"進入mehtod2");
            System.out.println(Thread.currentThread().getName()+"condition2  休眠");
            condition2.await();
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName()+"完成mehtod2");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            reentrantLock.unlock();
        }
    }

    public void method3(){
        try {
            reentrantLock.lock();
            System.out.println(Thread.currentThread().getName()+"進入mehtod3");
            System.out.println(Thread.currentThread().getName()+"喚醒condition1 休眠狀態的線程 ");
            condition1.signal();
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName()+"完成mehtod3");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            reentrantLock.unlock();
        }
    }

    public void method4(){
        try {
            reentrantLock.lock();
            System.out.println(Thread.currentThread().getName()+"進入mehtod4");
            System.out.println(Thread.currentThread().getName()+"休眠");
            System.out.println(Thread.currentThread().getName()+"喚醒condition2 休眠狀態的線程 ");
            condition2.signal();
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName()+"完成mehtod4");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            reentrantLock.unlock();
        }
    }

    public static void main(String[] args) {
        final ReentrantLock_eg reentrantLock_eg = new ReentrantLock_eg();
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                reentrantLock_eg.method1();
            }
        },"t1");
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                reentrantLock_eg.method2();
            }
        },"t2");

        Thread t3 = new Thread(new Runnable() {
            @Override
            public void run() {
                reentrantLock_eg.method3();
            }
        },"t3");

        Thread t4 = new Thread(new Runnable() {
            @Override
            public void run() {
                reentrantLock_eg.method4();
            }
        },"t4");

        t1.start();
        t2.start();
        t3.start();
        t4.start();
        // run output 
//        t1進入mehtod1
//        t1condition1  休眠
//        t2進入mehtod2
//        t2condition2  休眠
//        t3進入mehtod3
//        t3喚醒condition1 休眠狀態的線程
//        t3完成mehtod3
//        t1完成mehtod1
//        t4進入mehtod4
//        t4休眠
//        t4喚醒condition2 休眠狀態的線程
//        t4完成mehtod4
//        t2完成mehtod2
    }
}

3.ReentrantReadWriteLock

ReentrantReadWriteLock 讀寫鎖,多用於讀多寫少的情況。它的特點就是 讀讀共享 寫寫互斥,讀寫互斥

/**
 * Created by lyyz on 18-5-17.
 */
public class ReentrantReadWriteLock_eg {
    private ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();
    private ReentrantReadWriteLock.ReadLock readLock = reentrantReadWriteLock.readLock();
    private ReentrantReadWriteLock.WriteLock writeLock = reentrantReadWriteLock.writeLock();

    public void read(){
        try {
            readLock.lock();
            System.out.println("當前線程:" + Thread.currentThread().getName() + "進入...");
            Thread.sleep(3000);
            System.out.println("當前線程:" + Thread.currentThread().getName() + "退出...");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            readLock.unlock();
        }
    }

    public void write(){
        try {
            writeLock.lock();
            System.out.println("當前線程:" + Thread.currentThread().getName() + "進入...");
            Thread.sleep(3000);
            System.out.println("當前線程:" + Thread.currentThread().getName() + "退出...");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            writeLock.unlock();
        }
    }

    public static void main(String[] args) {

        ReentrantReadWriteLock_eg reentrantReadWriteLock_eg = new ReentrantReadWriteLock_eg();
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                reentrantReadWriteLock_eg.read();
            }
        },"t1");
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                reentrantReadWriteLock_eg.read();
            }
        },"t2");
        Thread t3 = new Thread(new Runnable() {
            @Override
            public void run() {
                reentrantReadWriteLock_eg.write();
            }
        },"t3");
        Thread t4 = new Thread(new Runnable() {
            @Override
            public void run() {
                reentrantReadWriteLock_eg.write();
            }
        },"t4");
        //讀讀共享,兩個線程可同時進行讀取
//        t1.start();
//        t2.start();
//        當前線程:t2進入...
//        當前線程:t1進入...
//        當前線程:t2退出...
//        當前線程:t1退出...
        //寫寫互斥 一個線程執行完以後另一個線程才能執行
//        t3.start();
//        t4.start();
//        當前線程:t3進入...
//        當前線程:t3退出...
//        當前線程:t4進入...
//        當前線程:t4退出...
        //讀寫互斥
//        t1.start();
//        t3.start();
//        當前線程:t1進入...
//        當前線程:t1退出...
//        當前線程:t3進入...
//        當前線程:t3退出...
    }

}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章