【Thread】- ReentrantLock、ReentrantReadWriteLock

Java鎖分類

  • 公平鎖:線程獲取鎖的順序是按照線程加鎖的順序分配,FIFO
  • 非公平鎖:獲取鎖的搶佔機制,是隨機獲取鎖的,通常由OS統一調度

ReentrantLock:可重入互斥鎖

ReentrantLock由最近成功獲取該鎖的線程全部,直到該線程釋放該鎖其餘的線程纔可獲取多線程

可重入互斥鎖解釋:可重入的意思是當線程進入同步代碼內部時,當在同步代碼內部訪問另外的同步方法,線程會自動獲取另外同步方法的鎖,換句話說當線程獲取一個同步代碼的鎖時,能夠自由訪問其餘的同步代碼dom

可重入特性本質:線程執行同步代碼時自動獲取到共享對象的監視器,只要是目標對象監視器做用範圍該線程均可徹底訪問,線程執行完同步代碼則釋放監聽器,其餘線程獲取監視器才能夠訪問,相似當司機拿着道路通行證能夠自由使用通行證規定的路段,通行證類比對象的監視器,司機離開路段,將通行證轉給另一個司機,同外一個司機也能夠享受一樣的服務(假設道路通行證不實名制)ide

特色:Lock鎖對象可徹底取代synchronized功能,而且更加靈活測試


Lock的基礎應用:this

測試類線程

public class LockDetail {
	
/**
    * 對象屬性爲Lock對象:static全部類實例共享
    * new ReentrantLock(false); 默認非公平鎖/true表示公平鎖
    */
private static Lock lock = new ReentrantLock();

public void show(String name) {
    
    try {
        lock.lock();
        for (int i = 0; i < name.length(); i++) {
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName() + ":" + name.charAt(i));
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        lock.unlock();
    }
}
}

測試代碼日誌

LockDetail lockDetail01 = new LockDetail();
LockDetail lockDetail02 = new LockDetail();

for(int i=0;i<10;i++){
    new Thread() {  
        public void run() {  
            lockDetail01.show("abcdefghijklmn");  
        };  
    }.start();  
    
    new Thread() {  
        public void run() {  
            lockDetail02.show("abcdefghijklmn");  
        };  
    }.start();  
}

效果code


讀寫鎖:ReentrantReadWriteLock

特色:容許多個線程同時讀,不容許同時寫對象

讀寫鎖測試類blog

class DefineLock {

// 建立讀寫鎖:讀鎖能夠同時讀,一個讀一個寫,不能兩個同時寫
ReadWriteLock lock = new ReentrantReadWriteLock();

int data = 0;

public void write() {

    lock.writeLock().lock(); // 線程綁定寫鎖

    this.data = new Random().nextInt(5000);
    System.out.println(Thread.currentThread().getName() + ":準備寫入數據");
    System.out.println(Thread.currentThread().getName() + ":寫入數據:" + data);
    System.out.println(Thread.currentThread().getName() + ":寫入完成");
    System.out.println("------------------------");

    lock.writeLock().unlock(); // 線程解除寫鎖
}

public void read() {

    lock.readLock().lock(); // 線程綁定讀鎖

    System.out.println(Thread.currentThread().getName() + ":準備讀取數據");
    System.out.println(Thread.currentThread().getName() + ":讀取數據:" + data);
    System.out.println(Thread.currentThread().getName() + ":準備讀取數據");
    System.out.println("-------------------------");

    lock.readLock().unlock(); // 線程綁定讀鎖
}
}

讀寫鎖測試代碼

DefineLock lockTest = new DefineLock();

		for (int i = 0; i < 20; i++) {

			boolean flag = (new Random().nextInt()%2 == 0);
			
			new Thread(new Runnable() {
				public void run() {
                    if(flag){					
					     lockTest.write();
                    }else{
                    	lockTest.read();
                    }
				}
			}).start();
		}
	}

效果

分析 日誌可看出每次寫入的數據都是不一樣的,不一樣的讀取線程讀取到的數據多是相同的,必定程度能夠說明多個線程讀和一個線程寫的讀寫鎖的特性,固然能夠將讀取的過程用sleep分割開,若是看到讀取線程交替就直接證實多線程讀和單線程寫的特性

可重入鎖特性測試

測試類

public class Test {
	
Lock lock = new ReentrantLock();

public void show1(String str) throws InterruptedException{
    
    lock.lock();
    
    for(int i = 0; i < str.length(); i++){
        System.out.println(Thread.currentThread().getName()+":show1:" + str.charAt(i));
        Thread.sleep(100);
    }
    show2(str);
    lock.unlock();
}

public void show2(String str) throws InterruptedException{
    
    lock.lock();
    
    for(int i = 0; i < str.length(); i++){
        System.out.println(Thread.currentThread().getName()+":show2:" + str.charAt(i));
        Thread.sleep(500);
    }
    
    lock.unlock();
}

public static void main(String[] args) {

    Test test = new Test();
    String str = "abcdefge";
    
    for(int i = 0; i < 20; i++){
        new Thread(new Runnable() {
        
        @Override
        public void run() {
            try {
            test.show1(str);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
            
        }
    }).start();
    } 
}
}

效果:

剖析: 控制檯輸出能夠看出每次都是單一線程執行完方法涉及到的同步代碼後另一個線程纔可訪問,直接證實可重入的特性

相關文章
相關標籤/搜索