欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Lock的使用---ReentrantLock

程序员文章站 2022-05-05 09:57:19
...

ReentrantLock类的作用如同Synchronized,旨在实现线程间的同步。

一、初识ReentrantLock

MyService.java

/*
 * ReentrantLock实现同步
 * lock.lock()持有锁
 * lock.unlock():一个线程执行完了以后释放锁
 * 结果都是分组输出的,但是哪个线程先输出是随机的
 */
public class MyService {
private Lock lock=new ReentrantLock();
public void testMethod(){
	lock.lock();
	for(int i=0;i<2;i++){
		System.out.println(Thread.currentThread().getName()+": "+i);
	}
	lock.unlock();
}
}
MyThread.java
public class MyThread extends Thread{
private MyService myservice;
	public MyThread(MyService myservice) {
		super();
		this.myservice=myservice;
	}
public void run(){
	myservice.testMethod();
}
}
Run.java
public class Run {
public static void main(String[] args){
	MyService myservice=new MyService();
	MyThread a1=new MyThread(myservice);
	MyThread a2=new MyThread(myservice);
	MyThread a3=new MyThread(myservice);
	MyThread a4=new MyThread(myservice);
	MyThread a5=new MyThread(myservice);
    a1.start();
    a2.start();
    a3.start();
    a4.start();
    a5.start();
}
}
结果如下:

Lock的使用---ReentrantLock

ReentrantLock类的lock()相当于上锁,unlock()相当于解锁。

二、Condition对象来实现等待/通知

Condition对象的await()方法相当于synchronized的wait()方法,signal()方法相当于notify()方法,singnAll()方法相当于notifyAll()方法。

Condition对象的一个好处是它可以选择性的通知,即选择性的唤醒部分线程,即在一个Lock对象里可以创建出多个Condition对象,synchronized相当于整个Lock对象只有一个单一的Condition对象。

注意的是Condition对象的signal()方法也不是立即释放锁,需要执行完此线程的同步代码块里的方法后才能释放搜,在调用await()和signal()方法之前都需要先调用lock.lock()来获得同步监视器。

MyService.java

/*
 * 使用多个Condition对象唤醒指定的线程。
 */
public class MyService {
private Lock lock=new ReentrantLock();
private Condition conditionA=lock.newCondition();
private Condition conditionB=lock.newCondition();
public void waitA(){
	try{
		lock.lock();
		System.out.println(Thread.currentThread().getName()+" begin waitA!");
		conditionA.await();
		System.out.println(Thread.currentThread().getName()+" end waitA!");
		}catch(InterruptedException e){
			e.printStackTrace();
		}finally{
			lock.unlock();
		}
}
public void waitB(){
	try{
		lock.lock();
		System.out.println(Thread.currentThread().getName()+" begin waitB!");
		conditionB.await();
		System.out.println(Thread.currentThread().getName()+" end waitB!");
	}catch(InterruptedException e){
		e.printStackTrace();
	}finally{
		lock.unlock();
	}
}
public void signalA(){
	try{
		lock.lock();
		System.out.println("A"+" begin signal!");
		conditionA.signalAll();
		System.out.println("A"+" end signal!");
	}finally{
		lock.unlock();
	}
}
public void signalB() {
	try{
		lock.lock();
		System.out.println("B"+" begin signal!");
		conditionB.signalAll();
		System.out.println("B"+" end signal!");
	}finally{
		lock.unlock();
	}
}
}
ThreadA.java
public class ThreadA extends Thread{
private MyService myservice;
	public ThreadA(MyService myservice) {
		super();
		this.myservice=myservice;
	}
public void run(){
	myservice.waitA();
}
}
ThreadB.java
public class ThreadB extends Thread{
private MyService myservice;
	public ThreadB(MyService myservice) {
		super();
		this.myservice=myservice;
	}
public void run(){
	myservice.waitB();
}
}
Run.java
public class Run {
public static void  main(String[] args) throws InterruptedException {
	MyService myservice=new MyService();
	ThreadA a=new ThreadA(myservice);
	a.setName("A");
	a.start();
	ThreadB b=new ThreadB(myservice);
	b.setName("B");
	b.start();
	Thread.sleep(3000);
	myservice.signalA();
	//myservice.signalB();
}
}
结果如下:

Lock的使用---ReentrantLock

上述Run方法中只唤醒了A线程,因此程序还在运行,B 线程还在等待。修改Run方法,把唤醒线程B 的代码加上,结果如下:

Lock的使用---ReentrantLock

等待/通知模式的案例当然少不了生产者/消费者模式的实现,主要注意消费者/生产者模式的多对多的交替打印,因为容易出现假死,注意两个点,一个是注意while而不同if,另一个是signalAll()而不是singnal()。

三、公平锁与非公平锁

公平锁表示线程获取锁的顺序是按照线程的加锁顺序来分配,即先进先出顺序;而非公平锁是一种获取锁的抢占机制,是随机获得锁的。

四、一些方法的介绍

1.getHoldCount()

查询当前线程保持此锁定的个数,即调用lock的次数。

2.getQueueLength()

返回正等待获取此锁定的线程数。比如有3个线程,其中一个线程执行了await,则此方法返回2,说明有2个线程正在同时等待lock的释放。

3.getWaitQueueLength()

返回等待与此锁定相关的给定条件Condition的线程估计数,比如有3个线程,每个线程都执行了同一个的condition对象的await方法,则调用此方法返回值是3。

4.hasQueuedThread(Thread thread)

查询指定线程是否正在等待获取此锁定。

5.hasQueuedThreads()

查询是否有线程正在等待获取此锁定。

6.hasWaiters()

查询是否有线程正在等待与此锁定相关的condition条件

7.isFair()

返回是否是公平锁

8.isHeldByCurrentThread()

查询当前线程是否保持此锁定。

9.isLocked()

查询此锁定是否由任意线程保持。

10.lockInterruptibly()

lock.lockInterruptibly :如果当前线程未被中断,则获取此锁定,如果已经被中断,则出现异常。

lock.lock :当前线程被中断爷不影响程序的进行。

11.awaitUninterruptibly()

Service.java

/*
 * condition.await() 当前线程被中断时,就会进入异常
 * condition.awaitUninterruptibly() 当前线程被中断时,不会出现异常
 */
public class Service {
private ReentrantLock lock=new ReentrantLock();
private Condition condition=lock.newCondition();
	public void testMethod(){
		try{
			lock.lock();
			System.out.println("wait begin!");
			//condition.await();
			condition.awaitUninterruptibly();
			System.out.println("wait end!");
		}finally{
			lock.unlock();
		}
	}
}
Run.java
public class Run {
public static void main(String[] args) throws InterruptedException{
	final Service service=new Service();
	Runnable t1=new Runnable() {
		@Override
		public void run() {
			service.testMethod();		
		}
	};
	Thread thread=new Thread(t1);
	thread.start();
	Thread.sleep(2000);
	thread.interrupt();
}
}
12.awaitUntil()

Service1.java

/*
 * condition.awaitUntil(calendar.getTime()) 超过这个时间,线程会自动的被唤醒
 * 同样在这个时间内,也可以被其他线程唤醒
 */
public class Service1 {
private ReentrantLock lock=new ReentrantLock();
private Condition condition=lock.newCondition();
public void waitMethod(){
	try{
		Calendar calendar=Calendar.getInstance();
		calendar.add(Calendar.SECOND,10);
		lock.lock();
		System.out.println("wait begin!");
		condition.awaitUntil(calendar.getTime());
		System.out.println("wait end!");
	}catch(InterruptedException e){
		e.printStackTrace();
	}finally{
		lock.unlock();
	}
}
public void notifyMethod(){
	try{
		Calendar calendar=Calendar.getInstance();
		calendar.add(Calendar.SECOND, 10);
		lock.lock();
		System.out.println("notify begin!");
		condition.signalAll();
		System.out.println("notify end!");
	}finally{
		lock.unlock();
	}
}
}
Run1.java
public class Run1 {
public static void main(String[] args){
	final Service1 service=new Service1();
	Runnable t1=new Runnable() {
		
		@Override
		public void run() {
			service.waitMethod();
		}
	};
	Runnable t2=new Runnable() {
		
		@Override
		public void run() {
		service.notifyMethod();
		}
	};
	Thread thread=new Thread(t1);
	thread.start();
	Thread thread1=new Thread(t2);
	thread1.start();
}
}
13.使用Condition对象实现顺序执行

Run2.java

/*
 * 使用Condition对象可以对线程执行的业务进行排序规划
 */
public class Run2 {
volatile private static int flag=1;
private static ReentrantLock lock=new ReentrantLock();
final private static Condition conditionA=lock.newCondition();
final private static Condition conditionB=lock.newCondition();
final private static Condition conditionC=lock.newCondition();
public static void main(String[] args){
	Thread threadA=new Thread(){
		public void run(){
			try{
				lock.lock();
				while(flag!=1){
					conditionA.await();
				}
				for(int i=0;i<3;i++){
					System.out.println("ThreadA "+i);
				}
				flag=2;
				conditionB.signalAll();
			}catch(InterruptedException e){
				e.printStackTrace();
			}finally{
				lock.unlock();
			}
		}
	};
	Thread threadB=new Thread(){
		public void run(){
			try{
				lock.lock();
				while(flag!=2){
					conditionB.await();
				}
				for(int i=0;i<3;i++){
					System.out.println("ThreadB "+i);
				}
				flag=3;
				conditionC.signalAll();
			}catch(InterruptedException e){
				e.printStackTrace();
			}finally{
				lock.unlock();
			}
		}
	};
	Thread threadC=new Thread(){
		public void run(){
			try{
			lock.lock();
			while(flag!=3){
				conditionC.await();
			}
			for(int i=0;i<3;i++){
				System.out.println("ThreadC "+i);
			}
			flag=1;
			conditionA.signalAll();
		}catch(InterruptedException e){
			e.printStackTrace();
		}finally{
			lock.unlock();
		}
			}
	};
	Thread[] aArray=new Thread[5];
	Thread[] bArray=new Thread[5];
	Thread[] cArray=new Thread[5];
    for(int i=0;i<5;i++){
    	aArray[i]=new Thread(threadA);
    	bArray[i]=new Thread(threadB);
    	cArray[i]=new Thread(threadC);
    	aArray[i].start();
    	bArray[i].start();
    	cArray[i].start();
    }
}
}

相关标签: ReentrantLock