java concurrent 线程通信_Java并发包——线程通信

Java并发包——线程通信

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

部分内容来自以下博客:

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 interfaceCondition {2 //使当前线程加入等待队列中并释放当锁,被通知、被中断时唤醒。

3 void await() throwsInterruptedException;4

5 //同await()类似,只是该方法对中断不敏感,只有被通知时才被唤醒。

6 voidawaitUninterruptibly();7

8 //同await()类似,如果在指定时间之内没有被通知或者被中断,该方法会返回false。

9 boolean await(long time, TimeUnit unit) throwsInterruptedException;10

11 //当前线程进入等待状态,被通知、中断或者超时之后被唤醒。返回值就是表示剩余的时间,超时返回值是0或者负数。

12 long awaitNanos(long nanosTimeout) throwsInterruptedException;13

14 //同awaitNanos(long nanosTimeout)类似,只是参数变成了指定日期。

15 boolean awaitUntil(Date deadline) throwsInterruptedException;16

17 //唤醒一个在等待队列中的线程。

18 voidsignal();19

20 //唤醒所有在等待队列中的线程。

21 voidsignalAll();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 classDemo {2 public static voidmain(String[] args) {3 DemoThread demoThread = newDemoThread();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 implementsRunnable {12 private Integer num = 1;13

14 @Override15 public voidrun() {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 classDemo {2 public static voidmain(String[] args) {3 DemoThread demoThread = newDemoThread();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 implementsRunnable {12 private Integer num = 1;13 Lock lock = newReentrantLock();14 Condition condition =lock.newCondition();15

16 @Override17 public voidrun() {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 classDemo {2 public static voidmain(String[] args) {3 DemoThread demoThread = newDemoThread();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 classDemoThread {14 static private Integer num = 0;15 static Lock lock = newReentrantLock();16 Condition c1 =lock.newCondition();17 Condition c2 =lock.newCondition();18 Condition c3 =lock.newCondition();19

20 public voidrun1() {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 voidrun2() {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 voidrun3() {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,就能明确的指定唤醒读线程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值