Java并发编程 之 同步队列与等待队列

在上一篇博客中,我简单的介绍了对Condition和ReentrantLock的使用,但是想要更好的掌握多线程编程,单单会用是不够的。这篇我会针对Condition方法中的await和signal的实现原理来梳理一下我的理解。

首先我们需要了解同步队列和等待队列的概念。简单的理解是同步队列存放着竞争同步资源的线程的引用(不是存放线程),而等待队列存放着待唤醒的线程的引用。

同步队列中存放着一个个节点,当线程获取同步状态失败时,同步器会将当前线程以及等待状态等信息构造成为一个节点并将其加入同步队列,首节点表示的获取同步状态成功的线程节点。


这里写图片描述

Condition维护着一个等待队列与同步队列相似。主要针对await和signal的操作。


这里写图片描述

现在不理解没关系,下面用实例来认识一下它们在多线程中是如何使用的。这里实现了三个多线程的run方法。A线程输出A然后通知B,然后B通知C。

public static class ThreadA extends Thread{
        @Override
        public void run(){
            try{
                lock.lock();
                System.out.println("A进程输出" + " : " + ++index);
                conditionB.signal();
                conditionA.await();
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                lock.unlock();
            }
        }
    }

    public static class ThreadB extends Thread{
        @Override
        public void run(){
            try{
                lock.lock();
                System.out.println("B进程输出" + " : " + ++index);
                conditionC.signal();
                conditionB.await();
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                lock.unlock();
            }
        }
    }

    public static class ThreadC extends Thread{
        @Override
        public void run(){
            try{
                lock.lock();
                System.out.println("C进程输出" + " : " + ++index);
                conditionA.signal();
                conditionC.await();
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                lock.unlock();
            }
        }
    }
public class CondtionTest {

    public static ReentrantLock lock = new ReentrantLock();
    public static Condition conditionA = lock.newCondition();
    public static Condition conditionB = lock.newCondition();
    public static Condition conditionC = lock.newCondition();
    public static int index = 0;
    public static void main(String[] args){
        ThreadA threadA = new ThreadA();
        ThreadB threadB = new ThreadB();
        ThreadC threadC = new ThreadC();

        threadA.start();//(1)
        threadB.start();//(2)
        threadC.start();//(3)
    }
}

当(1)(2)(3)三个线程被调用时,因为三个线程同时竞争lock,这里假设线程A拿到了lock(线程A虽然是看起来是先start(),但是正在的调用还是看调度程序的,所以这里只能假设是A线程拿到同步资源)。首节点表示的是正在操作同步资源的线程。所以现在的同步队列是:


这里写图片描述

接着线程A输出了:“A进程输出 : 1”。然后调用conditionB.signal(),其实这一步的signal是没什么意义的,因为conditionB现在没有线程是可以被唤醒的。
当conditionA.await()被执行到的时候,线程A同步队列中被移除,对应操作是锁的释放; 线程A(节点A)接着被加入到ConditionA等待队列,因为线程需要singal信号。

同步队列:


这里写图片描述

A等待队列:


这里写图片描述

现在在同步队列中的首节点是B节点,那么B线程占用了同步资源就可以开始运行了。先是输出“B进程输出 : 2”,同样的signal操作也是没有意义的,因为conditionC是没有可以被唤醒的线程。当conditionB.await()被执行到的时候,线程B同步队列中被移除,线程B(节点B)接着被加入到ConditionB等待队列

同步队列:


这里写图片描述

B等待队列:


这里写图片描述

终于轮到了C线程占用同步资源了,再输出“C进程输出:3”之后,调用conditionA.signal(),注意这个signal是有用的
因为在conditionA的等待队列中A线程是在等待的,把它取出来加入到同步队列中去竞争,但是这个时候线程A还没唤醒。首节点还是C。

同步队列:


这里写图片描述

接着conditionC.await()被执行。线程C同步队列中被移除,线程C(节点C)接着被加入到ConditionC等待队列

同步队列:


这里写图片描述

C等待队列:


这里写图片描述

注意到同步队列中的首节点已经变回了节点A了。所以线程A在刚刚等待的地方继续执行,最后释放了lock。但是线程B和线程C最后也没有其他线程去唤醒,状态一直为WAITING,而线程A的状态为TERMINATED

  • 30
    点赞
  • 62
    收藏
    觉得还不错? 一键收藏
  • 11
    评论
### 回答1: 《Java并发编程实战》是一本经典的Java并发编程指南,由Brian Goetz等人撰写。这本书针对Java多线程并发编程的实践问题给出了详细的解决方案和最佳实践。 该书的主要内容包括:线程安全性、对象的共享与发布、锁的优化、性能与可伸缩性、构建和组合对象、基础构建模块、任务执行、取消与关闭、线程池的使用、显式锁、构建自定义的同步工具等。 通过阅读这本书,读者可以了解Java中的各种并发问题,并学习如何设计和实现线程安全的Java应用。该书引入了很多并发编程的常见问题,例如:竞态条件、死锁、活跃性危险等,并提供了一些模式和技术来解决这些问题。 除了基础知识之外,该书还介绍了一些高级的并发编程概念,例如:并发集合、同步类、线程池等。这些内容将帮助读者更好地理解和利用Java并发编程能力。 总的来说,《Java并发编程实战》是一本权威而实用的Java并发编程指南,适合对多线程编程有一定了解的Java开发人员阅读。通过阅读这本书,读者可以更深入地理解Java并发编程的原理与应用,提高自己的并发编程能力。 ### 回答2: 《Java并发编程实战》是由美国计算机科学家布莱恩·戈策等人合著的一本书,是学习Java并发编程的经典教材。这本书系统地介绍了Java中的多线程并发和并行编程的基本知识和应用。该书分为三个部分,分别是基础篇、高级主题篇和专题扩展篇。 在基础篇中,书中详细介绍了Java内存模型、线程安全性、对象的共享、发布和逸出等概念。同时,还对Java中的锁、线程池、阻塞队列等常用并发工具进行了深入讲解,帮助读者理解并发编程的基本原理和机制。 高级主题篇则讨论了一些更加复杂的并发编程问题,如线程间的协作、线程间通信、并发集合类的使用和自定义的同步工具的设计等内容。该篇章通过讲解常见的并发问题和解决方案,提供了应对复杂并发场景的实践经验。 专题扩展篇主要讨论了一些与并发编程相关的主题,如并发性问题的调试与测试、程序性能调优等。这些内容能够帮助读者进一步提升对并发编程的理解和应用水平。 《Java并发编程实战》通过深入浅出的语言和大量实例,帮助读者掌握并发编程的基本概念和技术,为读者提供设计和编写高效多线程程序的实践经验。无论是Java初学者还是有一定经验的开发人员,都可以从中获得丰富的知识和实用的技巧,加速自己在并发编程领域的成长。 ### 回答3: 《Java并发编程实战》是一本经典的Java多线程编程指南,被广泛认可为学习并发编程的必读之作。本书由Brian Goetz等多位并发编程领域的专家合著,内容全面且深入浅出,适合从初学者到高级开发人员阅读。 该书分为四个部分,共16章。第一部分介绍了并发编程的基础知识,包括线程安全性、对象的共享、对象组合等。第二部分讲解了如何构建可复用的并发构件,包括线程安全性、发布与初始化安全性等。第三部分深入讨论了Java并发编程中常见的问题和挑战,例如活跃性、性能与可伸缩性等。第四部分则介绍了一些高级主题,如显式锁、原子变量和并发集合等。 书中包含了大量的示例代码和实践案例,可以帮助读者更好地理解并发编程的概念和技术。此外,本书还提供了一些最佳实践和经验教训,帮助读者避免常见的并发编程陷阱和错误。 《Java并发编程实战》从理论到实践的结合非常好,书中所介绍的内容都是经过实践验证的,具有很高的可靠性和实用性。无论是初学者还是有一定经验的开发人员,都可以从中获得实际应用的知识和经验。 综上所述,如果你想系统地学习Java并发编程,了解如何编写高效、可靠的多线程代码,那么《Java并发编程实战》是一本值得推荐的书籍。它可以帮助你深入理解并发编程的原理和技术,提高自己在并发编程领域的能力和水平。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值