java 多线程Condition接口的使用

来源:互联网 发布:php 执行cmd命令 编辑:程序博客网 时间:2024/05/29 03:34
java 多线程Condition接口的使用
java中条件变量都实现了java.util.concurrent.locks.Condition接口,条件变量的实例化是通过一个Lock对象上调用newCondition()方法来获取的,这样,条件就和一个锁对象绑定起来了。因此,Java中的条件变量只能和锁配合使用,来控制并发程序访问竞争资源的安全。
条件变量的出现是为了更精细控制线程等待与唤醒,在Java5之前,线程的等待与唤醒依靠的是Object对象的wait()和notify()/notifyAll()方法,这样的处
理不够精细。
基本使用方法:

(1)Lock接口的newCondition()方法:与锁绑定的所有条件对象都是通过Lock接口声明的newCondition()方法创建的,在使用条件的时候,必须获取这个条件绑定的锁,所以带条件的代码必须在调用Lock对象的lock()方法和unlock()方法之间。

(2)当线程调用条件的await()方法时,它将自动释放这个条件绑定的锁,其他某个线程才可以获取这个锁并且执行相同的操作,或者执行这个锁保护的另一个临界区代码。

(3)当一个线程调用了条件对象的signal()或者signalAll()方法后,一个或者多个在该条件上挂起的线程江北唤醒,但这并不能保证它们挂起的条件已经满足,所以必须在while循环中调用await(),在条件成立之前不能离开这个循环。如果条件不成立,将再次调用await()。

(4)必须小心使用await()和signal()方法,如果调用了一个条件的await()方法,却从不调用它的signal()方法,这个线程将永远休眠。(就是这个线程的执行结果其他线程是不知道的)

(5)因调用await()方法进入休眠的线程可能会被中断,所以必须处理InterruptedException异常。

(6)await(long time,TimeUnit unit),执行等待时间

先实现一个生产者和消费者模式看一下:主要看他是怎么使用的,之后再分析它的优势

import java.util.Date;import java.util.LinkedList;import java.util.List;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class COnditionDemo {public static void main (String[] args) {Buffer buffer = new Buffer(10);Producer producer = new Producer(buffer);Consumer consumer = new Consumer(buffer);for(int i = 0; i < 3; i++) {new Thread(producer,"producer-"+i).start();}for(int i = 0; i < 3; i++) {new Thread(consumer,"consumer"+i).start();}}}class Buffer {private final Lock lock;private final Condition notFull;private final Condition notEmpty;private int maxSize;private List<Date> storage;Buffer(int size) {//使用锁lock,并且创建两个condition,相当于两个阻塞队列lock = new ReentrantLock();notFull = lock.newCondition();notEmpty = lock.newCondition();maxSize = size;storage = new LinkedList<>();}public void put() {lock.lock();try {while (storage.size() == maxSize) {System.out.print(Thread.currentThread().getName()+":wait\n");notFull.await();//阻塞生产线程}storage.add(new Date());System.out.print(Thread.currentThread().getName()+": put:"+storage.size()+"\n");Thread.sleep(1000);notEmpty.signalAll();//唤醒消费线程} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}}public void take() {lock.lock();try {while (storage.size() == 0) {System.out.print(Thread.currentThread().getName()+": wait\n");notEmpty.await();//阻塞消费线程}Date d = ((LinkedList<Date>)storage).poll();System.out.print(Thread.currentThread().getName()+": take :"+storage.size()+"\n");Thread.sleep(1000);notFull.signalAll();//唤醒生产线程} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}}}class Producer implements Runnable {private Buffer buffer;Producer(Buffer b) {buffer = b;}@Overridepublic void run () {while(true) {buffer.put();}}}class Consumer implements Runnable {private Buffer buffer;Consumer(Buffer b) {buffer = b;}@Overridepublic void run () {while(true) {buffer.take();}}}
执行结果如下:
producer-0: put:1producer-0: put:2producer-0: put:3producer-0: put:4producer-0: put:5producer-0: put:6producer-0: put:7producer-0: put:8producer-0: put:9producer-0: put:10producer-0:waitproducer-2:waitproducer-1:waitconsumer0: take :9consumer0: take :8consumer0: take :7consumer0: take :6consumer0: take :5consumer0: take :4consumer0: take :3consumer0: take :2consumer0: take :1consumer0: take :0consumer0: waitconsumer1: waitconsumer2: waitproducer-0: put:1producer-0: put:2producer-0: put:3producer-0: put:4producer-0: put:5producer-0: put:6producer-0: put:7producer-0: put:8producer-0: put:9
。。。。。

上面这个程序的功能跟我我所熟悉的sychronized+notify+wait方式很类似,没错就是很类似。那condition的优势到底是什么呢?

Condition的强大之处在于它可以为多个线程间建立不同的Condition, 使用synchronized/wait()只有一个阻塞队列,notifyAll会唤起所有阻塞队列下的线程,而使用lock/condition,可以实现多个阻塞队列,signalAll只会唤起某个阻塞队列下的阻塞线程。

可能上面这段红色的字体,你有点不明白,没关系,我们经过下面这个例子,仔细看看,你就明白Condition的优势所在了!

import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class ConditionDemo2 {public static void main(String[] args) {final Business business = new Business();new Thread(new Runnable() {@Override public void run() {for(int i = 1; i <= 50; i++) {business.sub2(i);}}}).start();new Thread(new Runnable() {@Override public void run() {for(int i = 1; i <= 50; i++) {business.sub3(i);}}}).start();for(int i = 1; i <= 50; i++) {business.main(i);}}}class Business {private int shouldSub = 1;Lock lock = new ReentrantLock();Condition condition1 = lock.newCondition();//3个condition之间的唤醒Condition condition2 = lock.newCondition();Condition condition3 = lock.newCondition();public void sub2(int i) {lock.lock();try {while(shouldSub !=2 ) {try {condition2.await();} catch (Exception e) {e.printStackTrace();}}for(int j = 1; j <= 10; j++) {System.out.println("sub2 thread sequence of" + j + ",loop of " + i);}shouldSub = 3;condition3.signal();} finally {lock.unlock();}}public void sub3(int i) {lock.lock();try {while(shouldSub != 3) {try {condition3.await();} catch (Exception e) {e.printStackTrace();} }for(int j = 1;j <= 20; j++) {System.out.println("sub3 thread sequencxe of "+ j + ",loop of " + i);}shouldSub = 1;condition1.signal();} finally {lock.unlock();}}public void main(int i) {lock.lock();try {while(shouldSub != 1) {try {condition1.await();} catch (Exception e) {e.printStackTrace();} }for(int j = 1;j <= 100; j++) {System.out.println("sub3 thread sequencxe of "+ j + ",loop of " + i);}shouldSub = 2;condition2.signal();} finally {lock.unlock();}}} 



原创粉丝点击