`

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自动更新功能

    - **Notification**:当下载开始或进行时,应用会创建一个`Notification`对象,显示在通知栏,以展示下载进度。`NotificationCompat.Builder`可以用来创建兼容不同Android版本的通知。 - **更新进度**:`Download...

    react-native-in-app-notification-master.rar

    这个“react-native-in-app-notification-master”项目很显然是一个专注于在React Native应用内实现通知功能的库。通过分析其源码,我们可以深入理解如何在React Native中集成和管理应用内通知。 1. **项目结构**:...

    NGUI: Next-Gen3.0.7f1

    NGUI is a very powerful UI system and event notification framework. Features: -Full Inspector integration -No need to hit Play to see the results -What you see in the Scene view is what you get in ...

    谷歌地图 delphi 封装库 2013 0.1.9 全面支持google maps api

    - Improvement: TGMGeoCode -&gt; overrided Notification method to control Marker property - Improvement: TGMGeoCode -&gt; xxToStr and StrToxxx moved to the TTransform class into the GMFunctions unit - ...

    Android ApiDemos示例解析(26):App->Notification->IncomingMessage

    本文将深入解析`ApiDemos`中的一个特定示例——`App-&gt;Notification-&gt;IncomingMessage`,帮助开发者更好地理解和应用Android的通知功能。 通知(Notification)是Android系统中一种关键的用户界面元素,它在状态栏中...

    NGUI: Next-Gen UI 3.12.1

    NGUI is a very powerful UI system and event notification framework. Features - Editor integration, WYSIWYG - Localization, data binding, delegates, events - Supports all platforms - Make UIs that ...

    Android代码-react-native-push-notification

    React Native Local and Remote Notifications for iOS and Android Supported React Native Versions Component Version RN Versions README 1.0.7 = 2.1.0 &gt;= 0.33 Installation npm install --save ...

    Laravel开发-laravel-push-notification Push Notification 服务端支持

    在本文中,我们将深入探讨如何使用 Laravel 框架中的 "laravel-push-notification" 扩展包来实现 Push Notification 的服务端支持。Push Notification 是移动应用中常见的功能,用于向用户实时发送消息、提醒或者...

    react-native-push-notification.zip

    React Native Push Notification是一个用于在React Native应用中实现本地通知和远程推送通知的库。这个库允许开发者在iOS和Android平台上集成推送通知功能,为用户提供实时的消息提醒,增强用户体验。下面将详细讲解...

    3gpp-parlayx-wsdl-Call notification.zip

    标题 "3gpp-parlayx-wsdl-Call notification.zip" 涉及的是3GPP(第三代合作伙伴计划)中的ParlayX Web服务接口规范,特别是关于呼叫通知(Call Notification)的功能。3GPP是一个国际标准组织,致力于开发和推广...

    JEDEC J-STD-048:2014 Notification Standard for Product Discontinuance - 完整英文电子版(8页).pdf

    JEDEC J-STD-048:2014 Notification Standard for Product Discontinuance JEDEC J-STD-048:2014 Notification Standard for Product Discontinuance 是一个由JEDEC(Joint Electron Device Engineering Council...

    Python库 | cdk-codepipeline-badge-notification-0.2.37.tar.gz

    资源分类:Python库 所属语言:Python 资源全名:cdk-codepipeline-badge-notification-0.2.37.tar.gz 资源来源:官方 安装方法:https://lanzao.blog.csdn.net/article/details/101784059

    极光推送JAVA服务端集成 jpush-api-java-client-master

    【极光推送JAVA服务端集成 jpush-api-java-client-master】是一个专门为Java开发者设计的极光推送(JPush)服务端SDK。极光推送是面向移动应用开发者提供的一套消息推送服务,它可以帮助开发者轻松实现向Android、...

    qy-wechat-notification.hpi

    Jenkins插件:在企业微信通知插件的基础上,添加了失败原因以及失败日志做为消息的一部分进行发送。

    Python库 | sentry-dingtalk-notification-1.0.5.tar.gz

    资源分类:Python库 所属语言:Python 资源全名:sentry-dingtalk-notification-1.0.5.tar.gz 资源来源:官方 安装方法:https://lanzao.blog.csdn.net/article/details/101784059

    Laravel开发-laravel-push-notification

    "Laravel开发-laravel-push-notification"指的是一个专门针对Laravel框架的扩展包,它允许开发者轻松地在各种平台上,如Apple Push Notification Service (APN) 和 Firebase Cloud Messaging (FCM) 发送推送通知。...

    Android 源码:toast_and_notification

    Android 源码:toast_and_notification,100ms延迟后,振动250ms,停止100ms后振动500ms,没有搞懂具体是干什么用的,本人非专业人士,发在源码爱好者,供喜欢的人研究。

    oracle:Heap size 3597K exceeds notification threshold

    ### Oracle:“Heap size 3597K exceeds notification threshold” 解决方案 #### 背景与问题描述 在Oracle数据库环境中,可能会遇到一条警告信息:“Heap size 3597K exceeds notification threshold”。这条消息...

    删除环聊:trade_mark:的屏幕共享通知「Remove Screenshare Notification for Hangouts:trade_mark:」-crx插件

    当与某人共享屏幕时,移除Google Hangout窗口顶部的丑陋绿色通知栏。 您仍然可以通过单击环聊窗口左侧面板中的屏幕共享图标来选择停止共享。注意:如果在屏幕底部出现黑条,只需在任何方向上重新调整一次窗口大小...

    NGUI: Next-Gen UI v2018.3.0e 用户界面系统

    NGUI is a very powerful UI system and event notification framework. Features - Editor integration, WYSIWYG - Localization, data binding, delegates, events - Supports all platforms - Make UIs that...

Global site tag (gtag.js) - Google Analytics