java 线程 condition_java多线程-Condition

Condition 将 Object 监视器方法(wait、notify 和 notifyAll)分解成截然不同的对象,以便通过将这些对象与任意 Lock 实现组合使用,为每个对象提供多个等待 set(wait-set)。其中,Lock 替代了 synchronized 方法和语句的使用,Condition 替代了 Object 监视器方法的使用。

先看一个关于Condition使用的简单实例:

1 public classConditionTest {2 public static voidmain(String[] args) {3 final Lock lock = newReentrantLock();4 final Condition condition =lock.newCondition();5

6 Thread thread1 = new Thread(newRunnable() {7 @Override8 public voidrun() {9 try{10 lock.lock();11 System.out.println("我需要等一个信号"+this);12 condition.await();13 System.out.println("我拿到一个信号"+this);14 } catch(Exception e) {15 //TODO: handle exception

16 } finally{17 lock.unlock();18 }19

20

21 }22 }, "thread1");23 thread1.start();24 Thread thread2 = new Thread(newRunnable() {25 @Override26 public voidrun() {27 try{28 lock.lock();29 System.out.println("我拿到了锁");30 Thread.sleep(500);31 System.out.println("我发出一个信号");32 condition.signal();33 } catch(Exception e) {34 //TODO: handle exception

35 } finally{36 lock.unlock();37 }38

39

40 }41 }, "thread2");42 thread2.start();43 }44 }

运行结果:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 我需要等一个信号com.luchao.traditionalthread.ConditionTest$1@10bc3c92 我拿到了锁3 我发出一个信号4 我拿到一个信号com.luchao.traditionalthread.ConditionTest$1@10bc3c9

View Code

可以看到,Condition的执行方式,是当在线程1中调用await方法后,线程1将释放锁,并且将自己沉睡,等待唤醒,线程2获取到锁后,开始做事,完毕后,调用Condition的signal方法,唤醒线程1,线程1恢复执行。

以上说明Condition是一个多线程间协调通信的工具类,使得某个,或者某些线程一起等待某个条件(Condition),只有当该条件具备( signal 或者 signalAll方法被带调用)时 ,这些等待线程才会被唤醒,从而重新争夺锁。

Condition与传统线程通信有些类似,它的使用更广,可以将多个线程进行通信,以完成更加复杂的通信。

用Condition替换传统线程通信,在前面的传统有一个子线程和主线程交替运行50次的实例,使用Condition也可以完成。

代码如下:

1 public classConditionCommuniction {2 public static voidmain(String[] args) {3 final Business business = newBusiness();4 new Thread(newRunnable() {5 @Override6 public voidrun() {7 for (int i = 0; i < 50; i++) {8 business.sub(i);9 }10 }11 }).start();12 for (int i = 0; i < 50; i++) {13 business.main(i);14 }15 }16

17

18 static classBusiness{19 private Lock lock = newReentrantLock();20 private boolean isMain = true;21 private Condition condition =lock.newCondition();22 public void main(inti){23 lock.lock();24 try{25 while(!isMain){26 condition.await();27 }28 for (int j = 0; j < 100; j++) {29 System.out.println("main is looping :" + j +" in " +i);30 }31 isMain = false;32 condition.signal();33 } catch(Exception e) {34 //TODO: handle exception

35 } finally{36 lock.unlock();37 }38 }39 public void sub(inti){40 lock.lock();41 try{42 while(isMain){43 condition.await();44 }45 for (int j = 0; j < 10; j++) {46 System.out.println("sub is looping :" + j +" in " +i);47 }48 isMain = true;49 condition.signal();50 } catch(Exception e) {51 //TODO: handle exception

52 } finally{53 lock.unlock();54 }55 }56 }57 }

在Condition中,用await()替换wait(),用signal()替换notify(),用signalAll()替换notifyAll(),传统线程的通信方式,Condition都可以实现,这里注意,Condition是被绑定到Lock上的,要创建一个Lock的Condition必须用newCondition()方法。

这样看来,Condition和传统的线程通信没什么区别,Condition的强大之处在于它可以为多个线程间建立不同的Condition,下面引入API中的一段代码,加以说明。

1 classBoundedBuffer {2 final Lock lock = new ReentrantLock();//锁对象

3 final Condition notFull = lock.newCondition();//写线程条件

4 final Condition notEmpty = lock.newCondition();//读线程条件

5

6 final Object[] items = new Object[100];//缓存队列

7 int putptr/*写索引*/, takeptr/*读索引*/, count/*队列中存在的数据个数*/;8

9 public void put(Object x) throwsInterruptedException {10 lock.lock();11 try{12 while (count == items.length)//如果队列满了

13 notFull.await();//阻塞写线程

14 items[putptr] = x;//赋值

15 if (++putptr == items.length) putptr = 0;//如果写索引写到队列的最后一个位置了,那么置为0

16 ++count;//个数++

17 notEmpty.signal();//唤醒读线程

18 } finally{19 lock.unlock();20 }21 }22

23 public Object take() throwsInterruptedException {24 lock.lock();25 try{26 while (count == 0)//如果队列为空

27 notEmpty.await();//阻塞读线程

28 Object x = items[takeptr];//取值

29 if (++takeptr == items.length) takeptr = 0;//如果读索引读到队列的最后一个位置了,那么置为0

30 --count;//个数--

31 notFull.signal();//唤醒写线程

32 returnx;33 } finally{34 lock.unlock();35 }36 }37 }

这就是多个Condition的强大之处,假设缓存队列中已经存满,那么阻塞的肯定是写线程,唤醒的肯定是读线程,相反,阻塞的肯定是读线程,唤醒的肯定是写线程,那么假设只有一个Condition会有什么效果呢,缓存队列中已经存满,这个Lock不知道唤醒的是读线程还是写线程了,如果唤醒的是读线程,皆大欢喜,如果唤醒的是写线程,那么线程刚被唤醒,又被阻塞了,这时又去唤醒,这样就浪费了很多时间。

将上面主线程和子线程交替运行的程序进行扩展,三个线程交替运行,代码如下:

1 public classThreeConditionCommunication {2 public static voidmain(String[] args) {3 final Business business = newBusiness();4 new Thread(newRunnable() {5

6 @Override7 public voidrun() {8 for (int i = 0; i < 50; i++) {9 business.sub1(i);10 }11 }12 }).start();13 new Thread(newRunnable() {14

15 @Override16 public voidrun() {17 for (int i = 0; i < 50; i++) {18 business.sub2(i);19 }20 }21 }).start();22 for (int i = 0; i < 50; i++) {23 business.main(i);24 }25 }26 static classBusiness{27 Lock lock = newReentrantLock();28 Condition main =lock.newCondition();29 Condition sub1 =lock.newCondition();30 Condition sub2 =lock.newCondition();31 int runNum = 1;32

33 public void main(inti){34 lock.lock();35 try{36 while(runNum!=1){37 main.await();//主线程等待

38 }39 for (int j = 0; j < 100; j++) {40 System.out.println("main is looping of "+j+" in "+i);41 }42 runNum = 2;43 sub1.signal();//唤醒子线程1

44 } catch(Exception e) {45 //TODO: handle exception

46 } finally{47 lock.unlock();48 }49 }50 public void sub1(inti){51 lock.lock();52 try{53 while(runNum!=2){54 sub1.await();//子线程1等待

55 }56 for (int j = 0; j < 10; j++) {57 System.out.println("sub1 is looping of "+j+" in "+i);58 }59 runNum = 3;60 sub2.signal();//唤醒子线程2

61 } catch(Exception e) {62 //TODO: handle exception

63 } finally{64 lock.unlock();65 }66 }67 public void sub2(inti){68 lock.lock();69 try{70 while(runNum!=3){71 sub2.await();//子线程2等待

72 }73 for (int j = 0; j < 20; j++) {74 System.out.println("sub2 is looping of "+j+" in "+i);75 }76 runNum = 1;77 main.signal();//唤醒主线程

78 } catch(Exception e) {79 //TODO: handle exception

80 } finally{81 lock.unlock();82 }83 }84 }85 }

由此可见,Condition在多线程通信的强大作用,可以大大提高程序效率。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值