线程锁ReentrantLock和Condition的使用

来源:互联网 发布:淘宝怎么查宝贝降权 编辑:程序博客网 时间:2024/06/05 10:20

我们通过一个实际的例子来解释Condition的用法:

我们要打印1到9这9个数字,由A线程先打印1,2,3,然后由B线程打印4,5,6,然后再由A线程打印7,8,9. 这道题有很多种解法,现在我们使用Condition来做这道题(使用Object的wait,notify方法的解法在这里)。

package cn.outofmemory.locks;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class App {static class NumberWrapper {public int value = 1;}public static void main(String[] args) {//初始化可重入锁final Lock lock = new ReentrantLock();//第一个条件当屏幕上输出到3final Condition reachThreeCondition = lock.newCondition();//第二个条件当屏幕上输出到6final Condition reachSixCondition = lock.newCondition();//NumberWrapper只是为了封装一个数字,一边可以将数字对象共享,并可以设置为final//注意这里不要用Integer, Integer 是不可变对象final NumberWrapper num = new NumberWrapper();//初始化A线程Thread threadA = new Thread(new Runnable() {@Overridepublic void run() {//需要先获得锁lock.lock();try {System.out.println("threadA start write");//A线程先输出前3个数while (num.value <= 3) {System.out.println(num.value);num.value++;}//输出到3时要signal,告诉B线程可以开始了reachThreeCondition.signal();} finally {lock.unlock();}lock.lock();try {//等待输出6的条件reachSixCondition.await();System.out.println("threadA start write");//输出剩余数字while (num.value <= 9) {System.out.println(num.value);num.value++;}} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}}});Thread threadB = new Thread(new Runnable() {@Overridepublic void run() {try {lock.lock();while (num.value <= 3) {//等待3输出完毕的信号reachThreeCondition.await();}} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}try {lock.lock();//已经收到信号,开始输出4,5,6System.out.println("threadB start write");while (num.value <= 6) {System.out.println(num.value);num.value++;}//4,5,6输出完毕,告诉A线程6输出完了reachSixCondition.signal();} finally {lock.unlock();}}});//启动两个线程threadB.start();threadA.start();}}

 上述代码中有完整的注释,请参考注释,理解Condition的用法。

基本思路就是首先要A线程先写1,2,3,这时候B线程应该等待reachThredCondition信号,而当A线程写完3之后就通过signal告诉B线程“我写到3了,该你了”,这时候A线程要等嗲reachSixCondition信号,同时B线程得到通知,开始写4,5,6,写完4,5,6之后B线程通知A线程reachSixCondition条件成立了,这时候A线程就开始写剩下的7,8,9了。

为了更好的理解Condition的用法,我们再看下java官方提供的例子:

package locks;import java.util.Random;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class AppOfficial {/** * BoundedBuffer 是一个定长100的集合,当集合中没有元素时,take方法需要等待,直到有元素时才返回元素 * 当其中的元素数达到最大值时,要等待直到元素被take之后才执行put的操作 * @author yukaizhao * */static class BoundedBuffer {final Lock lock = new ReentrantLock();final Condition notFull = lock.newCondition();final Condition notEmpty = lock.newCondition();final Object[] items = new Object[100];int putptr, takeptr, count;public void put(Object x) throws InterruptedException {System .out.println("put wait lock");lock.lock();System.out.println("put get lock");try {while (count == items.length) {System.out.println("buffer full, please wait");notFull.await();}items[putptr] = x;if (++putptr == items.length)putptr = 0;++count;notEmpty.signal();} finally {lock.unlock();}}public Object take() throws InterruptedException {System.out.println("take wait lock");lock.lock();System.out.println("take get lock");try {while (count == 0) {System.out.println("no elements, please wait");notEmpty.await();}Object x = items[takeptr];if (++takeptr == items.length)takeptr = 0;--count;notFull.signal();return x;} finally {lock.unlock();}}}public static void main(String[] args) {final BoundedBuffer boundedBuffer = new BoundedBuffer();Thread t1 = new Thread(new Runnable() {@Overridepublic void run() {System.out.println("t1 run");for (int i=0;i<1000;i++) {try {System.out.println("putting..");boundedBuffer.put(Integer.valueOf(i));} catch (InterruptedException e) {e.printStackTrace();}}}}) ;Thread t2 = new Thread(new Runnable() {@Overridepublic void run() {for (int i=0;i<1000;i++) {try {Object val = boundedBuffer.take();System.out.println(val);} catch (InterruptedException e) {e.printStackTrace();}}}}) ;t1.start();t2.start();}}

这个示例中BoundedBuffer是一个固定长度的集合,这个在其put操作时,如果发现长度已经达到最大长度,那么会等待notFull信号,如果得到notFull信号会像集合中添加元素,并发出notEmpty的信号,而在其take方法中如果发现集合长度为空,那么会等待notEmpty的信号,同时如果拿到一个元素,那么会发出notFull的信号。

0 0
原创粉丝点击