ReentrantLock类和Condition类的使用

来源:互联网 发布:淘宝收藏的宝贝失效了 编辑:程序博客网 时间:2024/06/01 09:15

java多线程处理时使用synchronized关键字来实现线程之间的互斥,

如果你的jdk高于1.5,可以使用新增的ReentrantLock类实现互斥的效果,

功能比使用synchronized有所增强。

一 ReentrantLock实现同步效果

服务类:

package com.lanhuigu.JavaBase.thread.reentrantlock;import java.util.concurrent.locks.ReentrantLock;public class MyService {private ReentrantLock lock = new ReentrantLock();public void serviceMethod() {lock.lock();for (int i = 0; i < 10; i++) {System.out.println("ThreadName = " + Thread.currentThread().getName()+ ", valiable = " + (i + 1));}lock.unlock();}}
线程类:

package com.lanhuigu.JavaBase.thread.reentrantlock;public class MyThread extends Thread{private MyService service;public MyThread(MyService service) {// TODO Auto-generated constructor stubsuper();this.service = service;}@Overridepublic void run() {// TODO Auto-generated method stubservice.serviceMethod();}}

测试类:

package com.lanhuigu.JavaBase.thread.reentrantlock;public class RunTest {public static void main(String[] args) {MyService service = new MyService();MyThread t1 = new MyThread(service);MyThread t2 = new MyThread(service);MyThread t3 = new MyThread(service);MyThread t4 = new MyThread(service);MyThread t5 = new MyThread(service);t1.setName("A");t2.setName("B");t3.setName("C");t4.setName("D");t5.setName("E");t1.start();t2.start();t3.start();t4.start();t5.start();}}

运行结果:

ThreadName = A, valiable = 1
ThreadName = A, valiable = 2
ThreadName = A, valiable = 3
ThreadName = A, valiable = 4
ThreadName = A, valiable = 5
ThreadName = A, valiable = 6
ThreadName = A, valiable = 7
ThreadName = A, valiable = 8
ThreadName = A, valiable = 9
ThreadName = A, valiable = 10
ThreadName = C, valiable = 1
ThreadName = C, valiable = 2
ThreadName = C, valiable = 3
ThreadName = C, valiable = 4
ThreadName = C, valiable = 5
ThreadName = C, valiable = 6
ThreadName = C, valiable = 7
ThreadName = C, valiable = 8
ThreadName = C, valiable = 9
ThreadName = C, valiable = 10
ThreadName = B, valiable = 1
ThreadName = B, valiable = 2
ThreadName = B, valiable = 3
ThreadName = B, valiable = 4
ThreadName = B, valiable = 5
ThreadName = B, valiable = 6
ThreadName = B, valiable = 7
ThreadName = B, valiable = 8
ThreadName = B, valiable = 9
ThreadName = B, valiable = 10
ThreadName = D, valiable = 1
ThreadName = D, valiable = 2
ThreadName = D, valiable = 3
ThreadName = D, valiable = 4
ThreadName = D, valiable = 5
ThreadName = D, valiable = 6
ThreadName = D, valiable = 7
ThreadName = D, valiable = 8
ThreadName = D, valiable = 9
ThreadName = D, valiable = 10
ThreadName = E, valiable = 1
ThreadName = E, valiable = 2
ThreadName = E, valiable = 3
ThreadName = E, valiable = 4
ThreadName = E, valiable = 5
ThreadName = E, valiable = 6
ThreadName = E, valiable = 7
ThreadName = E, valiable = 8
ThreadName = E, valiable = 9
ThreadName = E, valiable = 10

从运行结果可以看到,每个线程访问时先调用lock锁定,

打印完数据后调用unlock方法释放锁,其他线程才能继续打印数据。

打印的数据按线程持有锁分组的,但是线程运行顺序是随机的,

也即线程的启动顺序与线程的运行顺序无关。

二 ReentrantLock类与Condition类配合实现等待/通知机制

关键字synchronized与wait()合notify()或notifyAll()结合可以实现等待/通知机制。

而ReentrantLock和Condition配合也可以实现等待/通知机制。


使用notify()和notifyAll()无法选择性的通知线程。

使用Condition的优点就是可以在Lock对象里面创建多个Condition(对象监视器)实例,

线程对象可以注册在指定的Condition中,从而实现有选择性地进行线程通知,使线程调度更加的灵活。


Condition类中常用方法:

await() 使线程等待相当于Object对象中的wait()方法

await(long time, TimeUnit unit)相当于Object对象中的wait(long timeout)方法

signal() 通知单个线程相当于Object对象中的notify()方法

signalAll() 通知所有线程相当于Object对象中的notifyAll()方法


单个Condition实现等待/通知机制实例:

Service服务类:

package com.lanhuigu.JavaBase.thread.reentrantlock2;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class MyService {private Lock lock = new ReentrantLock();private Condition condition = lock.newCondition();/** * 等待 */public void await() {try {lock.lock();System.out.println("await time:" + System.currentTimeMillis());condition.await(); // 使线程处于等待状态} catch (InterruptedException ex) {// 线程中断异常// TODO: handle exceptionex.printStackTrace();} finally {lock.unlock();}}/** * 通知 */public void signal() {try {lock.lock();System.out.println("signal time:" + System.currentTimeMillis());condition.signal();// 通知等待线程进行唤醒} catch (IllegalMonitorStateException ex) {// 监视器不合法异常// TODO: handle exceptionex.printStackTrace();} finally {lock.unlock();}}}

线程:

package com.lanhuigu.JavaBase.thread.reentrantlock2;public class MyThread extends Thread{private MyService service;public MyThread(MyService service) {// TODO Auto-generated constructor stubsuper();this.service = service;}@Overridepublic void run() {// TODO Auto-generated method stubservice.await();}}

测试类:

package com.lanhuigu.JavaBase.thread.reentrantlock2;/** * 关键字synchronized与wait()合notify()或notifyAll()结合可以实现等待/通知机制。 * 而ReentrantLock和Condition配合也可以实现等待/通知机制。 *  * 使用notify()和notifyAll()无法选择性的通知线程。 * 使用Condition的优点就是可以在Lock对象里面创建多个Condition(对象监视器)实例, * 线程对象可以注册在指定的Condition中,从而实现有选择性地进行线程通知,使线程调度更加的灵活。 *  * Condition类中常用方法: * await() 使线程等待相当于Object对象中的wait()方法 * await(long time, TimeUnit unit)相当于Object对象中的wait(long timeout)方法 * signal() 通知单个线程相当于Object对象中的notify()方法 * signalAll() 通知所有线程相当于Object对象中的notifyAll()方法 */public class RunTest {public static void main(String[] args) {try {MyService service = new MyService();MyThread myThread = new MyThread(service);/* * 线程启动后执行run方法,调用MyService中的await()方法, * 使得线程处于等待状态 */myThread.start();Thread.sleep(5000);// 当前线程(main线程)休眠5秒后往下执行/* * 调用signal方法,通知MyService中Condition(监视器)中注册的线程 * 进行唤醒执行 */service.signal();} catch (InterruptedException ex) {// TODO: handle exceptionex.printStackTrace();}}}

测试结果:


将运行结果signal time与await time做差,结果为5000毫秒,

正好为RunTest类中Thread.sleep(5000)的5000毫秒,

实现了等待/通知机制。

三 多个Condition通知部分线程

上面实例分析了线程指定单个Condition实现等待/通知机制,

但是,当多个线程多个Condition时,如何实现通知部分线程?

实例分析:

创建Service类:

package com.lanhuigu.JavaBase.thread.reentrantlock3;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class MyService {private Lock lock = new ReentrantLock();private Condition conditionA = lock.newCondition();private Condition conditionB = lock.newCondition();/** * A等待 */public void awaitA() {try {lock.lock();System.out.println("waitA begin time: " + System.currentTimeMillis());conditionA.await();// 等待System.out.println("waitA end time: " + System.currentTimeMillis());} catch (InterruptedException ex) {// TODO: handle exceptionex.printStackTrace();} finally {lock.unlock();}}/** * B等待 */public void awaitB() {try {lock.lock();System.out.println("waitB begin time: " + System.currentTimeMillis());conditionB.await();// 等待System.out.println("waitB end time: " + System.currentTimeMillis());} catch (InterruptedException ex) {// TODO: handle exceptionex.printStackTrace();} finally {lock.unlock();}}/** * conditionA通知: * signal() 通知单个线程 * signalAll() 通知所有线程 */public void signalAll_A() {try {lock.lock();System.out.println("signalAll_A begin time: " + System.currentTimeMillis()+ ", ThreadName = " + Thread.currentThread().getName());conditionA.signalAll();// 通知conditionA监视器中所有处于等待的线程进行唤醒} catch (IllegalMonitorStateException ex) {// TODO: handle exceptionex.printStackTrace();} finally {lock.unlock();}}/** * conditionB通知: * signal() 通知单个线程 * signalAll() 通知所有线程 */public void signalAll_B() {try {lock.lock();System.out.println("signalAll_B begin time: " + System.currentTimeMillis()+ ", ThreadName = " + Thread.currentThread().getName());conditionB.signalAll();// 通知conditionB监视器中所有处于等待的线程进行唤醒} catch (IllegalMonitorStateException ex) {// TODO: handle exceptionex.printStackTrace();} finally {lock.unlock();}}}

线程A:

package com.lanhuigu.JavaBase.thread.reentrantlock3;public class ThreadA extends Thread{private MyService service;public ThreadA(MyService service) {// TODO Auto-generated constructor stubsuper();this.service = service;}@Overridepublic void run() {// TODO Auto-generated method stubservice.awaitA();}}

线程B:

package com.lanhuigu.JavaBase.thread.reentrantlock3;public class ThreadB extends Thread{private MyService service;public ThreadB(MyService service) {// TODO Auto-generated constructor stubsuper();this.service = service;}@Overridepublic void run() {// TODO Auto-generated method stubservice.awaitB();}}

测试类:

package com.lanhuigu.JavaBase.thread.reentrantlock3;public class RunTest {public static void main(String[] args) {try {MyService service = new MyService();ThreadA threadA = new ThreadA(service);threadA.setName("AAAAA");threadA.start();ThreadB threadB = new ThreadB(service);threadB.setName("BBBBB");threadB.start();Thread.sleep(5000);// main线程休眠5秒,才执行后面的代码/* * 线程休眠5秒后开始执行service.signalAll_A(), * 单纯就是唤醒ThreadA线程,不唤醒ThreadB线程, * 这么测试的目的,就是想验证Condition能否做到只唤醒部分线程 */service.signalAll_A();} catch (Exception e) {// TODO: handle exceptione.printStackTrace();}}}

运行结果:


从运行结果可以看出,A经历了等待--唤醒--唤醒后执行,而B一直处于等待状态,未被唤醒。

线程注册时指定Condition,唤醒时根据Condition唤醒对应注册的线程,从而达到部分通知的能力。

阅读全文
0 0