多线程<九>demo Condition条件

本文深入讲解了Java并发编程中Condition的高级应用,通过具体实例演示了如何利用Condition实现更精细的线程控制,尤其是在多线程读写缓冲区场景下。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

假如你现在还在为自己的技术担忧,假如你现在想提升自己的工资,假如你想在职场上获得更多的话语权,假如你想顺利的度过35岁这个魔咒,假如你想体验BAT的工作环境,那么现在请我们一起开启提升技术之旅吧,详情请点击http://106.12.206.16:8080/qingruihappy/index.html

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()实现该缓冲区,当向缓冲区写入数据之后需要唤醒"读线程"时,不可能通过notify()或notifyAll()明确的指定唤醒"读线程",而只能通过notifyAll唤醒所有线程(但是notifyAll无法区分唤醒的线程是读线程,还是写线程)。  但是,通过Condition,就能明确的指定唤醒读线程。

 

 1 import java.util.concurrent.locks.Condition;
 2 import java.util.concurrent.locks.Lock;
 3 import java.util.concurrent.locks.ReentrantLock;
 4 
 5 class BoundedBuffer {
 6     final Lock lock = new ReentrantLock();
 7     final Condition notFull  = lock.newCondition(); 
 8     final Condition notEmpty = lock.newCondition(); 
 9 
10     final Object[] items = new Object[5];
11     int putptr, takeptr, count;
12 
13     public void put(Object x) throws InterruptedException {
14         lock.lock();    //获取锁
15         try {
16             // 如果“缓冲已满”,则等待;直到“缓冲”不是满的,才将x添加到缓冲中。
17             while (count == items.length)
18                 notFull.await();
19             // 将x添加到缓冲中
20             items[putptr] = x;
21            // System.out.println(items);
22             // 将“put统计数putptr+1”;如果“缓冲已满”,则设putptr为0。
23             if (++putptr == items.length) putptr = 0;
24             // 将“缓冲”数量+1
25             ++count;
26             // 唤醒take线程,因为take线程通过notEmpty.await()等待
27             notEmpty.signal();
28 
29             // 打印写入的数据
30             System.out.println(Thread.currentThread().getName() + " put  "+ (Integer)x);
31         } finally {
32             lock.unlock();    // 释放锁
33         }
34     }
35 
36     public Object take() throws InterruptedException {
37         lock.lock();    //获取锁
38         try {
39             // 如果“缓冲为空”,则等待;直到“缓冲”不为空,才将x从缓冲中取出。
40             while (count == 0) 
41                 notEmpty.await();
42             // 将x从缓冲中取出
43             Object x = items[takeptr]; 
44             // 将“take统计数takeptr+1”;如果“缓冲为空”,则设takeptr为0。
45             if (++takeptr == items.length) takeptr = 0;
46             // 将“缓冲”数量-1
47             --count;
48             // 唤醒put线程,因为put线程通过notFull.await()等待
49             notFull.signal();
50 
51             // 打印取出的数据
52             System.out.println(Thread.currentThread().getName() + " take "+ (Integer)x);
53             return x;
54         } finally {
55             lock.unlock();    // 释放锁
56         }
57     } 
58 }

 

 1 public class ConditionTest2 {
 2     private static BoundedBuffer bb = new BoundedBuffer();
 3 
 4     public static void main(String[] args) throws InterruptedException {
 5         // 启动10个“写线程”,向BoundedBuffer中不断的写数据(写入0-9);
 6         // 启动10个“读线程”,从BoundedBuffer中不断的读数据。
 7         for (int i=0; i<10; i++) {
 8             new PutThread("p"+i, i).start();
 9             Thread.sleep(100); 
10             new TakeThread("t"+i).start();
11         }
12     }
13 
14     static class PutThread extends Thread {
15         private int num;
16         public PutThread(String name, int num) {
17             super(name);
18             this.num = num;
19         }
20         public void run() {
21             try {
22                 Thread.sleep(1);    // 线程休眠1ms
23                 bb.put(num);        // 向BoundedBuffer中写入数据
24             } catch (InterruptedException e) {
25             }
26         }
27     }
28 
29     static class TakeThread extends Thread {
30         public TakeThread(String name) {
31             super(name);
32         }
33         public void run() {
34             try {
35                 Thread.sleep(10);
36                 Integer num = (Integer)bb.take();    // 从BoundedBuffer中取出数据
37             } catch (InterruptedException e) {
38             }
39         }
40     }
41 }

 

 1 p1 put  1
 2 p4 put  4
 3 p5 put  5
 4 p0 put  0
 5 p2 put  2
 6 t0 take 1
 7 p3 put  3
 8 t1 take 4
 9 p6 put  6
10 t2 take 5
11 p7 put  7
12 t3 take 0
13 p8 put  8
14 t4 take 2
15 p9 put  9
16 t5 take 3
17 t6 take 6
18 t7 take 7
19 t8 take 8
20 t9 take 9

 

 

结果说明
(01) BoundedBuffer 是容量为5的缓冲,缓冲中存储的是Object对象,支持多线程的读/写缓冲。多个线程操作“一个BoundedBuffer对象”时,它们通过互斥锁lock对缓冲区items进行互斥访问;而且同一个BoundedBuffer对象下的全部线程共用“notFull”和“notEmpty”这两个Condition。
       notFull用于控制写缓冲,notEmpty用于控制读缓冲。当缓冲已满的时候,调用put的线程会执行notFull.await()进行等待;当缓冲区不是满的状态时,就将对象添加到缓冲区并将缓冲区的容量count+1,最后,调用notEmpty.signal()缓冲notEmpty上的等待线程(调用notEmpty.await的线程)。 简言之,notFull控制“缓冲区的写入”,当往缓冲区写入数据之后会唤醒notEmpty上的等待线程。
       同理,notEmpty控制“缓冲区的读取”,当读取了缓冲区数据之后会唤醒notFull上的等待线程。
(02) 在ConditionTest2的main函数中,启动10个“写线程”,向BoundedBuffer中不断的写数据(写入0-9);同时,也启动10个“读线程”,从BoundedBuffer中不断的读数据。
(03) 简单分析一下运行结果。

 

 

 1 1, p1线程向缓冲中写入1。    此时,缓冲区数据:        | 1 |   |   |   |   |
 2      2, p4线程向缓冲中写入4。    此时,缓冲区数据:   | 1 | 4 |   |   |   |
 3      3, p5线程向缓冲中写入5。    此时,缓冲区数据:   | 1 | 4 | 5 |   |   |
 4      4, p0线程向缓冲中写入0。    此时,缓冲区数据:   | 1 | 4 | 5 | 0 |   |
 5      5, p2线程向缓冲中写入2。    此时,缓冲区数据:   | 1 | 4 | 5 | 0 | 2 |
 6      此时,缓冲区容量为5;缓冲区已满!如果此时,还有“写线程”想往缓冲中写入数据,会调用put中的notFull.await()等待,直接缓冲区非满状态,才能继续运行。
 7      6, t0线程从缓冲中取出数据1。此时,缓冲区数据:   |   | 4 | 5 | 0 | 2 |
 8      7, p3线程向缓冲中写入3。    此时,缓冲区数据:   | 3 | 4 | 5 | 0 | 2 |
 9      8, t1线程从缓冲中取出数据4。此时,缓冲区数据:   | 3 |   | 5 | 0 | 2 |
10      9, p6线程向缓冲中写入6。    此时,缓冲区数据:   | 3 | 6 | 5 | 0 | 2 |
11      9, p6线程向缓冲中写入6。    此时,缓冲区数据:   | 3 | 6 |   | 0 | 2 |
12      9, p6线程向缓冲中写入6。    此时,缓冲区数据:   | 3 | 6 | 7 | 0 | 2 |
13      9, p6线程向缓冲中写入6。    此时,缓冲区数据:   | 3 | 6 | 7 |   | 2 |
14      9, p6线程向缓冲中写入6。    此时,缓冲区数据:   | 3 | 6 | 7 | 8 | 2 |
15      9, p6线程向缓冲中写入6。    此时,缓冲区数据:   | 3 | 6 | 7 | 8 |   |
16      9, p6线程向缓冲中写入6。    此时,缓冲区数据:   |   | 6 | 7 | 8 | 9 |
17      9, p6线程向缓冲中写入6。    此时,缓冲区数据:   |   |   | 7 | 8 | 9 |
18      9, p6线程向缓冲中写入6。    此时,缓冲区数据:   |   |   |   | 8 | 9 |
19      9, p6线程向缓冲中写入6。    此时,缓冲区数据:   |   |   |   |   | 9 |
20      9, p6线程向缓冲中写入6。    此时,缓冲区数据:   |   |   |   |   |   |

 

假如你现在还在为自己的技术担忧,假如你现在想提升自己的工资,假如你想在职场上获得更多的话语权,假如你想顺利的度过35岁这个魔咒,假如你想体验BAT的工作环境,那么现在请我们一起开启提升技术之旅吧,详情请点击http://106.12.206.16:8080/qingruihappy/index.html

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值