jdk源码解析--Condition类
Posted 我的IT技术路
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了jdk源码解析--Condition类相关的知识,希望对你有一定的参考价值。
在之前的AQS中,我们有看到Condition类,条件等待,结合await、signal和Signalall进行使用,一般被来拿使用等待唤醒,避免程序轮询消耗cpu资源。本文我们来看一下condition类的使用。我们先看一个经典的面试题:三个线程1,2,3轮流打印10个数,线程1打印1,线程2打印2,线程3打印3,线程1打印4……
1. import java.util.ArrayDeque;
2. import java.util.Deque;
3. import java.util.concurrent.locks.Condition;
4. import java.util.concurrent.locks.ReentrantLock;
5. import java.util.stream.IntStream;
6.
7. public class ConditionTest {
8. public static void main(String[] args) {
9. Deque<Integer> deque = new ArrayDeque<>();
10. IntStream.range(1,11).forEach(deque::add);
11. ReentrantLock lock = new ReentrantLock();//创建锁
12. Condition c1 = lock.newCondition();//创建三个等待变量
13. Condition c2 = lock.newCondition();
14. Condition c3 = lock.newCondition();
15. Thread thread1 = new Thread(new PrintInfo(lock,c1,c2,deque));//创建三个线程
16. thread1.setName("thread_1");
17. thread1.start();
18. Thread thread2 = new Thread(new PrintInfo(lock,c2,c3,deque));
19. thread2.setName("thread_2");
20. thread2.start();
21. Thread thread3 = new Thread(new PrintInfo(lock,c3,c1,deque));
22. thread3.setName("thread_3");
23. thread3.start();
24. wakeUpC1(lock,c1);//唤醒第一个线程
25. }
26.
27. private static void wakeUpC1(ReentrantLock lock,Condition condition){
28. try {
29. Thread.sleep(100L);//主线程唤醒要等待3个线程都已经进入await状态
30. } catch (InterruptedException e) {
31. e.printStackTrace();
32. }
33. lock.lock();
34. try{
35. condition.signal();//唤醒第一个打印的线程
36. }catch (Exception ex){ }
37. finally {
38. lock.unlock();
39. }
40. }
41.
42. private static class PrintInfo implements Runnable{
43. private ReentrantLock lock ;//锁
44. private Condition myCondition;//阻塞本线程的条件变量
45. private Condition signalCondition;//唤醒下一个执行线程的条件变量
46. private Deque data;
47. public PrintInfo(ReentrantLock l,Condition c,Condition s,Deque i){
48. this.myCondition = c;
49. this.data = i;
50. this.lock = l;
51. this.signalCondition = s;
52. }
53. @Override
54. public void run() {
55. lock.lock();//加锁
56. try {
57. while (true) {//死循环
58. myCondition.await();//先阻塞,等待别人唤醒
59. if (data.size()>0){//如果还有数据需要打印
60. System.out.println(Thread.currentThread().getName()
61. + " print " + data.pollFirst());
62. signalCondition.signal();//唤醒下一个打印线程
63. }else {
64. signalCondition.signal();//没有数据了,唤醒下一个线程
65. break;//退出循环
66. }
67. }
68. } catch (Exception ex) { }
69. finally {
70. lock.unlock();//释放锁
71. }
72. }
73. }
74. }
执行结果如下 :
上面的例子是一个通过等待唤醒实现轮流打印的功能,在面试中还经常会被问到的消费者-生产者问题,其实现也需要用到等待唤醒,在线程池中的阻塞队列就类似于该功能,有兴趣的读者可以自行实现。这个在jdk源码讲完之后也会给出相应的例子,实现一个长度为10的阻塞队列。
以上是关于jdk源码解析--Condition类的主要内容,如果未能解决你的问题,请参考以下文章