Java并发包——线程通讯

Java并发包——线程通讯

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

部份内容来自如下博客:java

https://www.cnblogs.com/skywang12345/p/3496716.html多线程

线程通讯方式

对于线程之间的通讯方式,咱们以前使用Object.wait()和Object.notify(),经过与synchronized关键字进行同步,二者配合使用,能够实现线程之间的通讯。并发

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

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

使用Condition的优点

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

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

Condition

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

 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()方法。htm

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

Condition中的await()、signal()、signalAll()与Object中的wait()、notify()、notifyAll()区别

使用方式不一样

Condition中的await()方法至关于Object的wait()方法,Condition中的signal()方法至关于Object的notify()方法,Condition中的signalAll()至关于Object的notifyAll()方法。

不一样的是,Object中的这些方法是和同步锁捆绑使用的,而Condition是须要与互斥锁/共享锁捆绑使用的。

功能更增强大

Condition它更强大的地方在于:可以更加精细的控制多线程的休眠与唤醒。对于同一个锁,咱们能够建立多个Condition,在不一样的状况下使用不一样的Condition。

例如,假如多线程读/写同一个缓冲区:当向缓冲区中写入数据以后,唤醒“读线程”。当从缓冲区读出数据以后,唤醒“写线程”。当缓冲区满的时候,“写线程”须要等待。当缓冲区为空时,“读线程”须要等待。

若是采用Object类中的wait()、notify()、notifyAll()实现该缓冲区,当向缓冲区写入数据以后须要唤醒“读线程”时,不可能经过notify()或notifyAll()明确的指定唤醒"读线程",而只能经过notifyAll唤醒全部线程,可是notifyAll没法区分唤醒的线程是读线程,仍是写线程。

可是,经过Condition,就能明确的指定唤醒读线程。

相关文章
相关标签/搜索