1. 程式人生 > >多執行緒複習筆記之三【多執行緒中的Lock使用】

多執行緒複習筆記之三【多執行緒中的Lock使用】

Lock

1、getHoldCount()

查詢當前執行緒保持此鎖鎖定的個數,也就是呼叫lock方法的次數

2、int getQueueLength

返回正等待此鎖定的執行緒估計數,例如有5個執行緒,1個執行緒首先執行await,那麼呼叫getQueueLength返回4

3、int getWaitQueueLength(Condition condition)

返回等待與次鎖定相關的給定條件Condition的執行緒估計數,例如有5個執行緒,每個執行緒都執行了同一個condition物件的await方法,則呼叫此方法返回5.

4、boolean hasQueuedThreads

查詢是否有執行緒正在等待獲取此鎖定,lock.hasQueuedThread(thread)

5、boolean hasWaiters(Condition condition)

查詢是否有執行緒正在等待與此鎖定有關的condition條件

lock.hasWaiters(condition)執行緒數是lock.getWaitQueueLength(condition)

6、isFair

判斷是否是公平鎖

7、boolean isHeldByCurrentThread

查詢當前執行緒是否保持此鎖定

8、lockInterruptibly()

如果當前執行緒未被中斷,則獲取鎖定,如果已經被中斷則丟擲異常

9、boolean tryLock()

僅在呼叫時鎖定未被另一個執行緒保持的情況下,才獲取 該鎖定。

10、boolean tryLock(long timeout,TimeUnit unit)

如果鎖定給定等待時間內沒有被另一個執行緒保持,且當前執行緒未被中斷,則獲取該鎖定,例如:

package com.fyw.thread.lock;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class ServiceMethod {

	public ReentrantLock lock = new ReentrantLock();
	
	public Condition condition = lock.newCondition();
	
	public void awaitMethod(){
		try{
			if(lock.tryLock(3,TimeUnit.SECONDS)){
				System.out.println(Thread.currentThread().getName()+"獲得鎖的時間:"+System.currentTimeMillis());
				Thread.sleep(4000);
			}
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			if(lock.isHeldByCurrentThread()){
				lock.unlock();
			}
		}
	}
	
	public void notifyMethod(){
		try{
			lock.lock();
			System.out.println("有"+lock.getWaitQueueLength(condition)+"個執行緒等待condition");
			condition.signal();
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			lock.unlock();
		}
	}
}

public static void main(String[] args) throws InterruptedException {
		final ServiceMethod service = new ServiceMethod();
		
		Runnable runnable = new Runnable(){

			@Override
			public void run() {
				System.out.println(Thread.currentThread().getName()+"呼叫waitMethod時間:"+System.currentTimeMillis());
				service.awaitMethod();
			}
		};
		Thread threadA = new Thread(runnable);
		threadA.setName("A");
		threadA.start();
		Thread threadB = new Thread(runnable);
		threadB.setName("B");
		threadB.start();
		
	}

輸出:

A呼叫waitMethod時間:1544957162945
B呼叫waitMethod時間:1544957162945
A獲得鎖的時間:1544957162946

如果將sleep(4000)改成1000,輸出如下:

A呼叫waitMethod時間:1544957292643
B呼叫waitMethod時間:1544957292643
B獲得鎖的時間:1544957292643
A獲得鎖的時間:1544957293643

【使用Condition實現執行緒順序交叉執行】

package com.fyw.thread.lock.condition;

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

public class Run {

	volatile private static int nextRun = 1;
	
	private static Lock lock = new ReentrantLock();
	
	private static Condition condition1 = lock.newCondition();
	
	private static Condition condition2 = lock.newCondition();
	
	private static Condition condition3 = lock.newCondition();
	
	public static void main(String[] args) {
		Thread thread1 = new Thread(new Runnable(){

			@Override
			public void run() {
				try {
					lock.lock();
					while(nextRun != 1){
						condition1.await();
					}
					for(int i=0;i<3;i++){
						System.out.println("Thread1 "+(i+1));
					}
					nextRun = 2;
					condition2.signalAll();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}finally{
					lock.unlock();
				}
			}
			
		});
		
		Thread thread2 = new Thread(new Runnable(){

			@Override
			public void run() {
				try {
					lock.lock();
					while(nextRun != 2){
						condition2.await();
					}
					for(int i=0;i<3;i++){
						System.out.println("Thread2 "+(i+1));
					}
					nextRun = 3;
					condition3.signalAll();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}finally{
					lock.unlock();
				}
			}
			
		});
		
		Thread thread3 = new Thread(new Runnable(){

			@Override
			public void run() {
				try {
					lock.lock();
					while(nextRun != 3){
						condition3.await();
					}
					for(int i=0;i<3;i++){
						System.out.println("Thread3 "+(i+1));
					}
					nextRun = 1;
					condition1.signalAll();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}finally{
					lock.unlock();
				}
			}
			
		});
		
		Thread[] array1 = new Thread[5];
		Thread[] array2 = new Thread[5];
		Thread[] array3 = new Thread[5];
		
		for(int i=0;i<5;i++){
			array1[i] = new Thread(thread1);
			array2[i] = new Thread(thread2);
			array3[i] = new Thread(thread3);
			array1[i].start();
			array2[i].start();
			array3[i].start();
		}
	}
}

【執行結果如下】

Thread1 1
Thread1 2
Thread1 3
Thread2 1
Thread2 2
Thread2 3
Thread3 1
Thread3 2
Thread3 3
Thread1 1
Thread1 2
Thread1 3
Thread2 1
Thread2 2
Thread2 3
Thread3 1
Thread3 2
Thread3 3
Thread1 1
Thread1 2
Thread1 3
Thread2 1
Thread2 2
Thread2 3
Thread3 1
Thread3 2
Thread3 3
Thread1 1
Thread1 2
Thread1 3
Thread2 1
Thread2 2
Thread2 3
Thread3 1
Thread3 2
Thread3 3
Thread1 1
Thread1 2
Thread1 3
Thread2 1
Thread2 2
Thread2 3
Thread3 1
Thread3 2
Thread3 3

【讀寫鎖ReentrantReadWriteLock】

讀讀共享、讀寫互斥、寫寫互斥

【讀讀共享】

package com.fyw.thread.lock;

import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReadReadLock {

	private ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
	
	public void read(){
		try {
			readWriteLock.readLock().lock();
			System.out.println("執行緒"+Thread.currentThread().getName()+"在"+System.currentTimeMillis()+"獲得read鎖");
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}finally{
			readWriteLock.readLock().unlock();
		}
	}
	
	public static void main(String[] args) {
		ReadReadLock rrl = new ReadReadLock();
		ThreadA threadA = new ThreadA(rrl);
		threadA.setName("A");
		threadA.start();
		ThreadB threadB = new ThreadB(rrl);
		threadB.setName("B");
		threadB.start();
		
	}
}

【執行結果】

執行緒B並沒有等到Asleep(10000)之後再執行,而是一起執行

執行緒A在1544972110700獲得read鎖
執行緒B在1544972110701獲得read鎖

讀寫、寫寫用法同上