JUC学习——线程通信

时间:2019-06-15
本文章向大家介绍JUC学习——线程通信,主要包括JUC学习——线程通信使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

JUC学习——线程通信

摘要:本文主要学习了JUC并发包里有关线程通信的一些知识。

部分内容来自以下博客:

https://www.cnblogs.com/skywang12345/p/3496716.html

线程通信方式

对于线程之间的通信方式,我们之前使用Object.wait()和Object.notify(),通过与synchronized关键字进行同步,两者配合使用,可以实现线程之间的通信。

后来在JUC并发包里发现可以使用Lock取代synchronized关键字实现线程之间的同步,并且使用Lock的方式有比synchronized方式更加强大的功能,为了同Lock配合,实现线程之间的通信,就要用到Condition。

Condition的作用是对锁进行更精确的控制。Condition中的await()方法相当于Object的wait()方法,Condition中的signal()方法相当于Object的notify()方法,Condition中的signalAll()相当于Object的notifyAll()方法。不同的是,Object中的wait()、notify()、notifyAll()方法是和“同步锁”(synchronized关键字)捆绑使用的,而Condition是需要与“独享锁/共享锁”捆绑使用的。

使用Condition的优势

能够更加精细的控制多线程的休眠与唤醒。对于同一个锁,我们可以创建多个Condition,在不同的情况下使用不同的Condition。

能够在多个线程之间进行通信。Object的wait()、notify()、notifyAll()方法只能实现两个线程之间的通信,而Lock对象能通过newCondition()方法创建出无数的“条件”,通过这些条件,我们就能够成功地实现多线程之间的数据通信,对它们进行控制。

Condition

Condition是java.util.concurrent.locks包下的一个接口,提供了用来进行线程通信的方法。

 1 public interface Condition {
 2     // 使当前线程加入等待队列中并释放当锁,被通知、被中断时唤醒。
 3     void await() throws InterruptedException;
 4 
 5     // 同await()类似,只是该方法对中断不敏感,只有被通知时才被唤醒。
 6     void awaitUninterruptibly();
 7 
 8     // 同await()类似,如果在指定时间之内没有被通知或者被中断,该方法会返回false。
 9     boolean await(long time, TimeUnit unit) throws InterruptedException;
10 
11     // 当前线程进入等待状态,被通知、中断或者超时之后被唤醒。返回值就是表示剩余的时间,超时返回值是0或者负数。
12     long awaitNanos(long nanosTimeout) throws InterruptedException;
13 
14     // 同awaitNanos(long nanosTimeout)类似,只是参数变成了指定日期。
15     boolean awaitUntil(Date deadline) throws InterruptedException;
16 
17     // 唤醒一个在等待队列中的线程。
18     void signal();
19 
20     // 唤醒所有在等待队列中的线程。
21     void signalAll();
22 }

获取Lock上的特定Condition

Condition实例实质上被绑定到一个锁上。一个锁内部可以有多个Condition,即有多路等待和通知。要为特定Lock实例获得Condition实例,请使用Lock的newCondition()方法。

newCondition()返回用来与当前Lock实例一起使用的Condition实例。

类似于Object.wait()和Object.notify()的功能,Object.wait()与Object.notify()需要结合synchronized使用。Condition需要结合ReentrantLock使用。

使用Condition实现线程通信

使用synchronized和Object类的方法

使用synchronized和Object类的方法实现两个线程交替打印,代码如下:

 1 public class Demo {
 2     public static void main(String[] args) {
 3         DemoThread demoThread = new DemoThread();
 4         Thread a = new Thread(demoThread, "线程A");
 5         Thread b = new Thread(demoThread, "线程B");
 6         a.start();
 7         b.start();
 8     }
 9 }
10 
11 class DemoThread implements Runnable {
12     private Integer num = 1;
13 
14     @Override
15     public void run() {
16         synchronized (DemoThread.class) {
17             while (num <= 10) {
18                 DemoThread.class.notify();
19                 System.out.println(Thread.currentThread().getName() + " >>> " + num++);
20                 if (num <= 10) {
21                     try {
22                         DemoThread.class.wait();
23                     } catch (InterruptedException e) {
24                         e.printStackTrace();
25                     }
26                 }
27             }
28         }
29     }
30 }

运行结果如下:

 1 线程A >>> 1
 2 线程B >>> 2
 3 线程A >>> 3
 4 线程B >>> 4
 5 线程A >>> 5
 6 线程B >>> 6
 7 线程A >>> 7
 8 线程B >>> 8
 9 线程A >>> 9
10 线程B >>> 10

使用Lock和Condition类的方法

使用Lock和Condition类的方法实现两个线程交替打印,代码如下:

 1 public class Demo {
 2     public static void main(String[] args) {
 3         DemoThread demoThread = new DemoThread();
 4         Thread a = new Thread(demoThread, "线程A");
 5         Thread b = new Thread(demoThread, "线程B");
 6         a.start();
 7         b.start();
 8     }
 9 }
10 
11 class DemoThread implements Runnable {
12     private Integer num = 1;
13     Lock lock = new ReentrantLock();
14     Condition condition = lock.newCondition();
15 
16     @Override
17     public void run() {
18         lock.lock();
19         try {
20             while (num <= 10) {
21                 condition.signal();
22                 System.out.println(Thread.currentThread().getName() + " >>> " + num++);
23                 if (num <= 10) {
24                     condition.await();
25                 }
26             }
27         } catch (Exception e) {
28             e.printStackTrace();
29         } finally {
30             lock.unlock();
31         }
32     }
33 }

运行结果如下:

 1 线程A >>> 1
 2 线程B >>> 2
 3 线程A >>> 3
 4 线程B >>> 4
 5 线程A >>> 5
 6 线程B >>> 6
 7 线程A >>> 7
 8 线程B >>> 8
 9 线程A >>> 9
10 线程B >>> 10

使用Lock和Condition类的方法实现三个线程按顺序循环打印

使用Lock和Condition类的方法实现三个线程按顺序打印,需要唤醒指定的线程,代码如下:

 1 public class Demo {
 2     public static void main(String[] args) {
 3         DemoThread demoThread = new DemoThread();
 4         Thread a = new Thread(() -> demoThread.run1(), "线程1");
 5         Thread b = new Thread(() -> demoThread.run2(), "线程2");
 6         Thread c = new Thread(() -> demoThread.run3(), "线程3");
 7         a.start();
 8         b.start();
 9         c.start();
10     }
11 }
12 
13 class DemoThread {
14     static private Integer num = 0;
15     static Lock lock = new ReentrantLock();
16     Condition c1 = lock.newCondition();
17     Condition c2 = lock.newCondition();
18     Condition c3 = lock.newCondition();
19 
20     public void run1() {
21         try {
22             Thread.sleep(10);
23         } catch (InterruptedException e1) {
24             e1.printStackTrace();
25         }
26         lock.lock();
27         try {
28             while (num < 10) {
29                 for (int i = 0; i < 1 && num < 10; i++) {
30                     System.out.println(Thread.currentThread().getName() + " >>> " + num);
31                 }
32                 num++;
33                 c2.signal();
34                 c1.await();
35                 if (num >= 9) {
36                     c3.signal();
37                 }
38             }
39         } catch (Exception e) {
40             e.printStackTrace();
41         } finally {
42             lock.unlock();
43         }
44     }
45 
46     public void run2() {
47         try {
48             Thread.sleep(20);
49         } catch (InterruptedException e1) {
50             e1.printStackTrace();
51         }
52         lock.lock();
53         try {
54             while (num < 10) {
55                 for (int i = 0; i < 2 && num < 10; i++) {
56                     System.out.println(Thread.currentThread().getName() + " >>> " + num);
57                 }
58                 num++;
59                 c3.signal();
60                 c2.await();
61                 if (num >= 9) {
62                     c1.signal();
63                 }
64             }
65         } catch (Exception e) {
66             e.printStackTrace();
67         } finally {
68             lock.unlock();
69         }
70     }
71 
72     public void run3() {
73         try {
74             Thread.sleep(30);
75         } catch (InterruptedException e1) {
76             e1.printStackTrace();
77         }
78         lock.lock();
79         try {
80             while (num < 10) {
81                 for (int i = 0; i < 3 && num < 10; i++) {
82                     System.out.println(Thread.currentThread().getName() + " >>> " + num);
83                 }
84                 num++;
85                 c1.signal();
86                 c3.await();
87                 if (num >= 9) {
88                     c2.signal();
89                 }
90             }
91         } catch (Exception e) {
92             e.printStackTrace();
93         } finally {
94             lock.unlock();
95         }
96     }
97 }

运行结果如下:

 1 线程1 >>> 0
 2 线程2 >>> 1
 3 线程2 >>> 1
 4 线程3 >>> 2
 5 线程3 >>> 2
 6 线程3 >>> 2
 7 线程1 >>> 3
 8 线程2 >>> 4
 9 线程2 >>> 4
10 线程3 >>> 5
11 线程3 >>> 5
12 线程3 >>> 5
13 线程1 >>> 6
14 线程2 >>> 7
15 线程2 >>> 7
16 线程3 >>> 8
17 线程3 >>> 8
18 线程3 >>> 8
19 线程1 >>> 9

原文地址:https://www.cnblogs.com/shamao/p/11027759.html