【并发技术13】条件阻塞Condition的应用(二)

简介: 【并发技术13】条件阻塞Condition的应用

可以考虑一个问题,为啥要用两个 Condition 呢?之所以这么设计肯定是有原因的:如果用一个 Condition,现在假设队列满了,但是有 2 个线程 A 和 B 同时存数据,那么都进入了睡眠,好,现在另一个线程取走一个了,然后唤醒了其中一个线程 A,那么 A 可以存了,存完后, A 又唤醒一个线程,如果 B 被唤醒了,那就出问题了,因为此时队列是满的,B 不能存的,B存的话就会覆盖原来还没被取走的只,这就是一个 Condition 带来的问题。

来测试一下上面的阻塞队列的效果。

public class BoundedBuffer {
    public static void main(String[] args) {        
        Buffer buffer = new Buffer();       
        for(int i = 0; i < 5; i ++) { //开启5个线程往缓冲区存数据
            new Thread(new Runnable() {             
                @Override
                public void run() {
                    try {
                        buffer.put(new Random().nextInt(1000)); //随机存数据
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }
        for(int i = 0; i < 10; i ++) { //开启10个线程从缓冲区中取数据
            new Thread(new Runnable() {             
                @Override
                public void run() {
                    try {
                        buffer.take(); //从缓冲区取数据
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }
    }
}


我故意只开启 5 个线程存数据,10 个线程取数据,就是想让它出现取数据被阻塞的情况发生,看运行的结果。

Thread-5 被阻塞了,暂时无法取数据!

Thread-10 被阻塞了,暂时无法取数据!

Thread-1 存好了值: 755

Thread-0 存好了值: 206

Thread-2 存好了值: 741

Thread-3 存好了值: 381

Thread-14 取出了值: 755

Thread-4 存好了值: 783

Thread-6 取出了值: 206

Thread-7 取出了值: 741

Thread-8 取出了值: 381

Thread-9 取出了值: 783

Thread-5 被阻塞了,暂时无法取数据!

Thread-11 被阻塞了,暂时无法取数据!

Thread-12 被阻塞了,暂时无法取数据!

Thread-10 被阻塞了,暂时无法取数据!

Thread-13 被阻塞了,暂时无法取数据!

从结果中可以看出,线程 5 和10 抢先执行,发现队列中没有,于是就被阻塞了,睡在那了,知道队列中有新的值存入才可以取,但是他们两运气不好,存的数据又被其他线程前线取走了……可以多运行几次。如果想要看到存数据被阻塞,可以将取数据的线程设置少一点,这里我就不设了。


2.2 两个以上线程之间的唤醒


还是原来那个题目,现在让三个线程来执行,看一下题目:

有三个线程,子线程1先执行10次,然后子线程2执行10次,然后主线程执行5次,然后再切换到子线程1执行10次,子线程2执行10次,主线程执行5次……如此往返执行50次。

如果不用 Condition,还真不好弄,但是用 Condition 来做的话,就非常方便了,原理很简单,定义三个 Condition,子线程 1 执行完唤醒子线程 2,子线程 2 执行完唤醒主线程,主线程执行完唤醒子线程1。唤醒机制和上面那个缓冲区道理差不多,下面附上代码。

public class ThreeConditionCommunication {
    public static void main(String[] args) {
        Business bussiness = new Business();
        new Thread(new Runnable() {// 开启一个子线程
                    @Override
                    public void run() {
                        for (int i = 1; i <= 50; i++) {
                            bussiness.sub1(i);
                        }
                    }
                }).start();
        new Thread(new Runnable() {// 开启另一个子线程
            @Override
            public void run() {
                for (int i = 1; i <= 50; i++) {
                    bussiness.sub2(i);
                }
            }
        }).start();
        // main方法主线程
        for (int i = 1; i <= 50; i++) {
            bussiness.main(i);
        }
    }
    static class Business {
        Lock lock = new ReentrantLock();
        Condition condition1 = lock.newCondition(); //Condition是在具体的lock之上的
        Condition condition2 = lock.newCondition();
        Condition conditionMain = lock.newCondition();
        private int bShouldSub = 0;
        public void sub1(int i) {
            lock.lock();
            try {
                while (bShouldSub != 0) {
                    try {
                        condition1.await(); //用condition来调用await方法
                    } catch (Exception e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                for (int j = 1; j <= 10; j++) {
                    System.out.println("sub1 thread sequence of " + j
                            + ", loop of " + i);
                }
                bShouldSub = 1;
                condition2.signal(); //让线程2执行
            } finally {
                lock.unlock();
            }
        }
        public void sub2(int i) {
            lock.lock();
            try {
                while (bShouldSub != 1) {
                    try {
                        condition2.await(); //用condition来调用await方法
                    } catch (Exception e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                for (int j = 1; j <= 10; j++) {
                    System.out.println("sub2 thread sequence of " + j
                            + ", loop of " + i);
                }
                bShouldSub = 2;
                conditionMain.signal(); //让主线程执行
            } finally {
                lock.unlock();
            }
        }
        public void main(int i) {
            lock.lock();
            try {
                while (bShouldSub != 2) {
                    try {
                        conditionMain.await(); //用condition来调用await方法
                    } catch (Exception e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                for (int j = 1; j <= 5; j++) {
                    System.out.println("main thread sequence of " + j
                            + ", loop of " + i);
                }
                bShouldSub = 0;
                condition1.signal(); //让线程1执行
            } finally {
                lock.unlock();
            }
        }
    }
}


关于线程中 Condition 技术就分享这么多吧。


相关文章
|
6月前
|
算法 安全 调度
解决Python并发访问共享资源引起的竞态条件、死锁、饥饿问题的策略
解决Python并发访问共享资源引起的竞态条件、死锁、饥饿问题的策略
95 0
|
2月前
|
Java API 容器
JAVA并发编程系列(10)Condition条件队列-并发协作者
本文通过一线大厂面试真题,模拟消费者-生产者的场景,通过简洁的代码演示,帮助读者快速理解并复用。文章还详细解释了Condition与Object.wait()、notify()的区别,并探讨了Condition的核心原理及其实现机制。
死锁产生的条件是什么?
死锁是多个线程因为争夺资源而相互等待的一种状态,导致所有线程都无法继续执行下去。死锁产生的条件通常包括以下四个条件:
94 0
|
6月前
|
存储 安全 C++
《C++ Concurrencyin Action》第6章--基于锁的并发数据结构设计
《C++ Concurrencyin Action》第6章--基于锁的并发数据结构设计
《C++ Concurrencyin Action》第6章--基于锁的并发数据结构设计
|
6月前
|
Java
多线程并发之显示锁Lock与其通信方式Condition源码解读
多线程并发之显示锁Lock与其通信方式Condition源码解读
47 0
什么条件下会产出死锁,如何避免死锁?
一个去美团面试的小伙伴私我说,被面试官问到一个死锁的问题难道了,面试前还特意刷了题,面试的时候就是脑子一片空白不知道怎么回答。今天,我给大家彻底讲明白。
94 1
什么条件下会产出死锁,如何避免死锁?
【并发技术13】条件阻塞Condition的应用(一)
【并发技术13】条件阻塞Condition的应用
|
安全 算法
死锁原因,条件和解决
死锁原因,条件和解决
133 0
|
运维 Oracle 关系型数据库
Oracle优化02-锁和阻塞
Oracle优化02-锁和阻塞
127 0
并发编程之没有条件创造条件Condition
多线程编程必会内容, 锁条件Lock.Condition
114 0

相关实验场景

更多