`

java线程:Wait-And-Notification机制

 
阅读更多

 

Java的每一个对象除了有一个相关的monitor以外(用做synchronized lock),还有一个相关的wait set,用以存放处于WAITING状态的线程

 

  • wait set是线程的集合
  • 当Java对象创建的时候,其wait set是空的。对于wait set操作(将线程加入或移出wait set)都是原子操作
  • 对于wait set的操作(加入或移出),而且只能通过Object.wait,Object.notify,Object.notifyAll这三个操作来进行。当线程执行到Object.wait指令后,就会进入到wait set集合中;而执行到Object.notify,Object.notifyAll指令后,则通知处于wait set中的线程,条件满足了。

 

一、背后的理念

 

  • 一个线程需要某个条件继续执行,并且认为别的线程会创造这个条件。于是这个线程就呆在wait set里面等待
  • 当别的线程创造了这个条件,则通知等待条件的线程

 

二、相关的方法

 

void wait()

 

 

等待条件发生。

 

该方法必须在synchronized方法或synchronized块中呼叫

void wait(long timeout)

 

 

等待条件发生。但和wait()方法不同之处在于,如果在timeout(毫秒)的时间内,通知没有到来,则自己略过条件等待,移出wait set,继续执行。

 

该方法必须在synchronized方法或synchronized块中呼叫

void wait(long timeout,int nanos)

 

 

等待条件发生。观念和wait(long timeout)是一样的。唯一的差别timeout的时间,到了纳秒级别。

 

该方法必须在synchronized方法或synchronized块中呼叫

void notify()

 

 

通知位于wait set中的某一个线程,条件已经发生了。

 

该方法必须在synchronized方法或synchronized块中呼叫

void notifyAll()

 

 

通知位于wait set中的所有线程,条件已经发生了。

 

该方法必须在synchronized方法或synchronized块中呼叫

 

 

三、生产者和消费者模型的实现

第一种:

 

public class ProducerConsumerV6 {

    private List<Integer> list = null;

    private Random random = null;

    private Object lock;

    public ProducerConsumerV6() {
        list = new ArrayList<Integer>();
        random = new Random();
        lock = new Object();
    }

    public void produce() throws InterruptedException {
        synchronized (lock) {
            if (list.size() == 0) {// 这个对象的wait set里面有consumer线程
                lock.notifyAll();// notify() can work
            }
            System.out.print(Thread.currentThread().getName() + "\t\t\t" + list + "\t\t\t");
            int size = list.size();
            for (int i = 0; i < 10 - size; i++) {
                list.add(random.nextInt(1000));
            }
            System.out.println(list);
        }
    }

    /**
     * 这里有个问题,当producer产生的食物总量,比consumer的数量少的时候 则有可能发生发生一场状况
     * 
     * @throws InterruptedException
     */
    public void consume() throws InterruptedException {
        synchronized (lock) {
            while (list.size() == 0) {// 测试竞争条件
                // 注意这里必须用while,当一个consumer线程醒来的时候,还必须
                // 继续检查list是否为空,如果是则继续等待。否则就继续下一条指
                // 令执行
                lock.wait();
            }
            System.out.print(Thread.currentThread().getName() + "\t\t\t" + list + "\t\t\t");
            list.remove(0);
            System.out.println(list);
        }
    }

    public static void main(String[] args) throws Exception {
        ProducerConsumerV6 pc = new ProducerConsumerV6();
        for (int i = 0; i < 50; i++) {
            Thread thread = new Thread(pc.new Consumer());
            thread.setName("Consumer " + i);
            thread.start();
        }

        for (int i = 0; i < 2; i++) {
            Thread thread = new Thread(pc.new Producer());
            thread.setName("Producer " + i);
            thread.start();
        }
    }

    public class Producer implements Runnable {
        @Override
        public void run() {
            while (true) {
                try {
                    produce();
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    return;
                }
            }
        }
    }

    public class Consumer implements Runnable {
        @Override
        public void run() {
            while (true) {
                try {
                    consume();
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    return;
                }
            }
        }
    }
}
 

第二种:

 

public class ProducerConsumerV7 {

    private List<Integer> list = null;

    private Random random = null;

    public ProducerConsumerV7() {
        list = new ArrayList<Integer>();
        random = new Random();
    }

    public synchronized void produce() throws InterruptedException {
        if (list.size() == 0) {//这个对象的wait set里面有consumer线程
            notifyAll();//notify() can work
        }
        System.out.print(Thread.currentThread().getName() + "\t\t\t" + list + "\t\t\t");
        int size = list.size();
        for (int i = 0; i < 10 - size; i++) {
            list.add(random.nextInt(1000));
        }
        System.out.println(list);
    }
    
    /**
     * 这里有个问题,当producer产生的食物总量,比consumer的数量少的时候
     * 则有可能发生发生一场状况
     * @throws InterruptedException
     */
    public synchronized void consume() throws InterruptedException {
        while(list.size() == 0) {//测试竞争条件
             //注意这里必须用while,当一个consumer线程醒来的时候,还必须
             //继续检查list是否为空,如果是则继续等待。否则就继续下一条指
             //令执行
            wait();  
        }
        System.out.print(Thread.currentThread().getName() + "\t\t\t" + list + "\t\t\t");
        list.remove(0);
        System.out.println(list);
    }

    public static void main(String[] args) throws Exception {
        ProducerConsumerV7 pc = new ProducerConsumerV7();
        for (int i = 0; i < 50; i++) {
            Thread thread = new Thread(pc.new Consumer());
            thread.setName("Consumer " + i);
            thread.start();
        }

        for (int i = 0; i <2; i++) {
            Thread thread = new Thread(pc.new Producer());
            thread.setName("Producer " + i);
            thread.start();
        }
    }

    public class Producer implements Runnable {
        @Override
        public void run() {
            while (true) {
                try {
                    produce();
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    return;
                }
            }
        }
    }

    public class Consumer implements Runnable {
        @Override
        public void run() {
            while (true) {
                try {
                    consume();
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    return;
                }
            }
        }
    }
}
 

四,其他

 

  • Object.wait方法和Thread.sleep方法的不同之处在于,Object.wait方法需要获得对象的synchronized 锁――即对象的Monitor。Object.wait方法执行时,线程就会进入对象的wait set中,synchronized锁就会被自动释放掉(由JVM内部完成这个操作)。一旦接受到通知,线程从Object.wait中返回之前,必须首先获得synchronized锁。所以Java线程Wait-And-Notification机制,必须有赖于synchronized锁。所以上面表格中所列的几个方法必须在synchronized方法或synchronized块中执行。
  • 当线程从wait方法中唤醒以后,这时已经获取了synchronized锁,就会接着wait指令后面的指令继续执行。
  • notify() 和 notifyAll()方法类似,区别在于notifyAll会“唤醒”处于wait set中的所有的线程,只是这些线程仍需竞争synchronized lock。只有获取了synchronized lock的线程才能继续执行。(似乎这些线程的状态发生了迁移,从WAITING态迁移到了BLOCKED状态),而notify只是唤醒一个线程,但具体是哪个线程由JVM决定,我们自己对此无能为力。

 

参考: 

 

  • http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.2
  • 《Java Threads 3rd Edtion》

分享到:
评论

相关推荐

    新版Android开发教程.rar

    � Google 提供了一套 Java 核心包 (J2SE 5,J2SE 6) 的有限子集,尚不承诺遵守 Java 任何 Java 规范 , 可能会造 成J ava 阵营的进一步分裂。 � 现有应用完善度不太够,需要的开发工作量较大。--------------------...

    androidpn解决重连

    本文将从以下几个方面进行详细解析:服务管理、通知服务、XMPP管理器、持久连接监听器、通知包监听器、重新连接线程以及与这些组件相关的任务提交机制。 ### 一、服务管理(ServiceManager) 在AndroidPN中,`...

    小闹钟 Java源代码

    在Java编程领域,创建一个“小闹钟”应用程序是一个经典的实践项目,它涉及到多线程、时间处理和用户界面设计等多个关键知识点。下面我们将详细探讨这些核心概念。 首先,Java中的多线程是实现小闹钟功能的基础。在...

    小米2018春季实习生Android、iOS开发工程师笔试题合集

    6. **多线程**:Java提供了Thread类和Runnable接口来实现并发执行,理解同步和互斥的概念,熟悉synchronized关键字及wait()、notify()方法。 7. **输入/输出流**:Java.IO包中包括了各种流类,用于进行文件操作和...

    嵌入式八股文面试题库资料知识宝典-深圳禾苗通信科技有限公司.zip

    嵌入式八股文面试题库资料知识宝典-深圳禾苗通信科技有限公司.zip

    Arduino UART实验例程【正点原子EPS32S3】

    Arduino UART实验例程,开发板:正点原子EPS32S3,本人主页有详细实验说明可供参考。

    电力弹簧技术在主动配电网规划与运行优化调度中的应用研究

    内容概要:本文详细探讨了电力弹簧技术在主动配电网规划及运行优化调度中的应用。首先介绍了电力弹簧技术作为智能电网调控手段的优势,如自适应性强、响应速度快、节能环保等。接着阐述了主动配电网规划的目标和策略,包括优化电网结构、提高能源利用效率和降低故障风险。随后讨论了运行优化调度的原则和方法,强调了实时监测、智能调度策略以及优化调度模型的重要性。最后通过实际案例分析展示了电力弹簧技术在提升电网稳定性、可靠性和能效方面的显著效果,展望了其广阔的应用前景。 适合人群:从事电力系统规划、运行管理的研究人员和技术人员,以及对智能电网感兴趣的学者和学生。 使用场景及目标:适用于希望深入了解电力弹簧技术及其在主动配电网规划和运行优化调度中具体应用的专业人士。目标是掌握电力弹簧技术的工作原理、优势及其在实际项目中的实施方法。 其他说明:本文不仅提供了理论分析,还有具体的案例支持,有助于读者全面理解电力弹簧技术的实际应用价值。

    honor_1.145_testgray20250427.apk

    honor_1.145_testgray20250427.apk

    嵌入式八股文面试题库资料知识宝典-【开发】嵌入式开源项目&库&资料.zip

    嵌入式八股文面试题库资料知识宝典-【开发】嵌入式开源项目&库&资料.zip

    鸿蒙生态HarmonyOS:万物互联时代的操作系统革新与发展路径

    内容概要:本文详细介绍了华为推出的面向全场景的分布式操作系统HarmonyOS。HarmonyOS旨在打破设备间的壁垒,实现万物互联,通过分布式软总线和分布式任务调度等核心技术,让不同设备协同工作,如手机、平板、智能家居等设备间无缝流转任务。其应用生态涵盖教育、金融、出行等多个领域,华为通过资金、技术支持和流量扶持吸引开发者,推动生态繁荣。HarmonyOS从2019年首次发布至今,经历了多个版本迭代,性能和安全性不断提升,用户体验更加智能便捷。尽管面临应用生态丰富度不足、市场竞争压力等挑战,华为通过优化开发工具、加强市场推广等策略积极应对。未来,HarmonyOS将在分布式技术、AI融合和隐私安全等方面持续创新,并在智能家居、车联网、工业互联网等领域拓展生态。 适合人群:对操作系统技术感兴趣的专业人士、开发者、科技爱好者。 使用场景及目标:①了解HarmonyOS的技术架构和分布式技术的特点;②探讨HarmonyOS在智能家居、车联网等领域的应用前景;③评估HarmonyOS对现有操作系统市场的潜在影响。 阅读建议:HarmonyOS作为一款面向全场景的操作系统,不仅涉及技术实现,还包括生态建设和用户体验。因此,在阅读过程中,应重点关注其技术优势、应用场景及未来发展潜力,结合自身需求思考其在实际生活和工作中的应用价值。

    少儿编程scratch项目源代码文件案例素材-简单杀戮.zip

    少儿编程scratch项目源代码文件案例素材-简单杀戮.zip

    基于阻抗控制和工艺优化的机器人磨抛技术研究.pdf

    基于阻抗控制和工艺优化的机器人磨抛技术研究.pdf

    少儿编程scratch项目源代码文件案例素材-扛住别被压.zip

    少儿编程scratch项目源代码文件案例素材-扛住别被压.zip

    【操作系统领域】HarmonyOS架构解析:分布式设计与全场景智能应用的创新实践

    内容概要:本文详细介绍了华为自主研发的面向全场景的分布式操作系统——HarmonyOS的架构设计及其在智能家居、智能穿戴、智慧出行等领域的应用。HarmonyOS采用分层架构,包括内核层、系统服务层、框架层和应用层,各层分工明确,协同工作,为用户提供稳定、高效、智能的操作系统。其核心特性包括分布式架构、微内核设计、组件化开发和一次开发多端部署,这些特性使得不同设备能够实现互联互通和资源共享,为用户带来无缝的全场景智能体验。此外,文章还探讨了HarmonyOS面临的生态建设和兼容性挑战,以及未来的发展前景和技术创新方向。 适合人群:对操作系统架构感兴趣的科技爱好者、智能设备开发者及相关行业从业者。 使用场景及目标:①了解HarmonyOS架构设计及其在智能家居、智能穿戴、智慧出行等领域的具体应用;②掌握HarmonyOS的核心特性,如分布式架构、微内核设计、组件化开发和一次开发多端部署;③探讨HarmonyOS面临的挑战及其未来发展方向。 其他说明:HarmonyOS的出现不仅为华为在智能设备领域的发展提供了有力支撑,也为整个行业的创新发展注入了新的活力。作为科技爱好者和关注者,我们应持续关注HarmonyOS的发展,共同见证它在智能设备领域创造更多的辉煌。

    嵌入式八股文面试题库资料知识宝典-linux驱动开发.zip

    嵌入式八股文面试题库资料知识宝典-linux驱动开发.zip

    开关磁阻电机技术参数与建模技术深度解析:4kW电机性能详述

    内容概要:本文深入探讨了一款额定功率为4kW的开关磁阻电机,详细介绍了其性能参数如额定功率、转速、效率、输出转矩和脉动率等。同时,文章还展示了利用RMxprt、Maxwell 2D和3D模型对该电机进行仿真的方法和技术,通过外电路分析进一步研究其电气性能和动态响应特性。最后,文章提供了基于RMxprt模型的MATLAB仿真代码示例,帮助读者理解电机的工作原理及其性能特点。 适合人群:从事电机设计、工业自动化领域的工程师和技术人员,尤其是对开关磁阻电机感兴趣的科研工作者。 使用场景及目标:适用于希望深入了解开关磁阻电机特性和建模技术的研究人员,在新产品开发或现有产品改进时作为参考资料。 其他说明:文中提供的代码示例仅用于演示目的,实际操作时需根据所用软件的具体情况进行适当修改。

    嵌入式八股文面试题库资料知识宝典-新岸线.zip

    嵌入式八股文面试题库资料知识宝典-新岸线.zip

    基于支持向 量机和余弦相似度的故障诊断方法.pdf

    基于支持向 量机和余弦相似度的故障诊断方法.pdf

    Objective-C+ARKit实现图片识别、平面捕捉、人脸识别+源码(毕业设计&课程设计&项目开发)

    Objective-C+ARKit实现图片识别、平面捕捉、人脸识别+源码,适合毕业设计、课程设计、项目开发。项目源码已经过严格测试,可以放心参考并在此基础上延申使用 ARKit实现图片识别、平面捕捉、人脸识别 ARKit需要ios11 以及 A11处理器或更高版本设备支持 Objective-C+ARKit实现图片识别、平面捕捉、人脸识别+源码,适合毕业设计、课程设计、项目开发。项目源码已经过严格测试,可以放心参考并在此基础上延申使用 ARKit实现图片识别、平面捕捉、人脸识别 ARKit需要ios11 以及 A11处理器或更高版本设备支持~ Objective-C+ARKit实现图片识别、平面捕捉、人脸识别+源码,适合毕业设计、课程设计、项目开发。项目源码已经过严格测试,可以放心参考并在此基础上延申使用 ARKit实现图片识别、平面捕捉、人脸识别 ARKit需要ios11 以及 A11处理器或更高版本设备支持

    少儿编程scratch项目源代码文件案例素材-火柴人大战 中世纪战争.zip

    少儿编程scratch项目源代码文件案例素材-火柴人大战 中世纪战争.zip

Global site tag (gtag.js) - Google Analytics