jdk源码解析--Condition类

Posted 我的IT技术路

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了jdk源码解析--Condition类相关的知识,希望对你有一定的参考价值。

在之前的AQS中,我们有看到Condition类,条件等待,结合awaitsignalSignalall进行使用,一般被来拿使用等待唤醒,避免程序轮询消耗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类的主要内容,如果未能解决你的问题,请参考以下文章

jdk源码解析--LongAdder类

jdk源码解析--AbstractStringBuilder类

jdk源码解析--String 类

jdk源码解析--BitSet类

jdk源码解析--Writer类

jdk源码解析--WeakReference/softReference类