Java线程和多线程(二)——对象中的wait,notify以及notifyAll方法
Java对象中的wait,notify以及notifyAll方法
在Java的Object类中包含了3个final的方法,这三个方法允许线程来交流资源是否被锁定。这三个方法就是wait(),notify()以及notifyAll().
在对象上调用这三个方法的线程需要包含一个对象监视器(锁),否则就会抛出java.lang.IllegalMonitorStateException异常。
wait方法
对象的wait方法有三个,一个是令对象等待任何线程来调用notify或者notifyAll方法来令该对象在当前线程唤醒。另外两个将当前线程置于等待状态,等到特定的时间来唤醒。
- wait()
- wait(long millis)
- wait(long millis, int nanos)
notify方法
notify方法仅仅唤醒一个线程,令线程开始执行。所以,如果有多个线程等待一个对象的时候,这个方法只能唤醒一个线程。而唤醒的线程的选择是依赖于操作系统对于线程的管理的。
notifyAll方法
notifyAll方法会唤醒所有等待改对象的线程,尽管哪一个线程会优先执行时取决于操作系统的线程调度的。
以上的三个方法都可以用来实现生产者消费者问题。 
其中,消费者线程会等待队列中的对象而生产者将对象放入队列并唤醒所有等待的线程。
下面的例子将解释多线程如何在同一个对象上使用wait,notify以及notifyAll方法。
Message类
参考代码,Message类就是我们操作的wait,notify以及notifyAll方法的对象:
package com.sapphire.concurrency;
public class Message {
    private String msg;
    public Message(String str){
        this.msg=str;
    }
    public String getMsg() {
        return msg;
    }
    public void setMsg(String str) {
        this.msg=str;
    }
}Waiter类
Waiter类的对象会等待其他线程调用notify方法来完成其执行:
package com.sapphire.concurrency;
public class Waiter implements Runnable{
    private Message msg;
    public Waiter(Message m){
        this.msg=m;
    }
    @Override
    public void run() {
        String name = Thread.currentThread().getName();
        synchronized (msg) {
            try{
                System.out.println(name+" waiting to get notified at time:"+System.currentTimeMillis());
                msg.wait();
            }catch(InterruptedException e){
                e.printStackTrace();
            }
            System.out.println(name+" waiter thread got notified at time:"+System.currentTimeMillis());
            //process the message now
            System.out.println(name+" processed: "+msg.getMsg());
        }
    }
}Notifier类
Notifier类是处理Message对象,然后调用notify方法来唤醒等待Message对象的线程的:
package com.sapphire.concurrency;
public class Notifier implements Runnable {
    private Message msg;
    public Notifier(Message msg) {
        this.msg = msg;
    }
    @Override
    public void run() {
        String name = Thread.currentThread().getName();
        System.out.println(name+" started");
        try {
            Thread.sleep(1000);
            synchronized (msg) {
                msg.setMsg(name+" Notifier work done");
                msg.notify();
                // msg.notifyAll();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}测试代码
package com.sapphire.concurrency;
public class WaitNotifyTest {
    public static void main(String[] args) {
        Message msg = new Message("process it");
        Waiter waiter = new Waiter(msg);
        new Thread(waiter,"waiter").start();
        Waiter waiter1 = new Waiter(msg);
        new Thread(waiter1, "waiter1").start();
        Notifier notifier = new Notifier(msg);
        new Thread(notifier, "notifier").start();
        System.out.println("All the threads are started");
    }
}当我们执行上面的程序时,我们会看到如下的输出,但是程序不会结束,因为有两个线程在等待Message对象,而我们调用的notify方法仅仅唤醒了其中的一个线程,另一个线程仍然处于等待状态,等待被唤醒。
waiter waiting to get notified at time:1356318734009
waiter1 waiting to get notified at time:1356318734010
All the threads are started
notifier started
waiter waiter thread got notified at time:1356318735011
waiter processed: notifier Notifier work done如果我们调整前面的代码,在Notifier类中调用notifyAll而不是调用notify方法的话,将会有如下输出:
waiter waiting to get notified at time:1356318917118
waiter1 waiting to get notified at time:1356318917118
All the threads are started
notifier started
waiter1 waiter thread got notified at time:1356318918120
waiter1 processed: notifier Notifier work done
waiter waiter thread got notified at time:1356318918120
waiter processed: notifier Notifier work done这是因为notifyAll()方法唤醒了所有的Waiter线程,所以程序完成了全部执行。
Java线程和多线程(二)——对象中的wait,notify以及notifyAll方法的更多相关文章
- 【Java并发系列02】Object的wait()、notify()、notifyAll()方法使用
		一.前言 对于并发编程而言,除了Thread以外,对Object对象的wati和notify对象也应该深入了解其用法,虽然知识点不多. 二.线程安全基本知识 首先应该记住以下基本点,先背下来也无妨: ... 
- Java Object对象中的wait,notify,notifyAll的理解
		wait,notify,notifyAll 是定义在Object类的实例方法,用于控制线程状态,在线程协作时,大家都会用到notify()或者notifyAll()方法,其中wait与notify是j ... 
- Java 线程池(二)
		简介 在上篇 Java 线程池(一) 我们介绍了线程池中一些的重要参数和具体含义,这篇我们看一看在 Java 中是如何去实现线程池的,要想用好线程池,只知其然是远远不够的,我们需要深入实现源码去了解线 ... 
- java工具类之按对象中某属性排序
		import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang ... 
- Java 多线程学习笔记:wait、notify、notifyAll的阻塞和恢复
		前言:昨天尝试用Java自行实现生产者消费者问题(Producer-Consumer Problem),在coding时,使用到了Condition的await和signalAll方法,然后顺便想起了 ... 
- 多线程协作wait、notify、notifyAll方法简介理解使用 多线程中篇(十四)
		在锁与监视器中有对wait和notify以及notifyAll进行了简单介绍 所有对象都有一个与之关联的锁与监视器 wait和notify以及notifyAll之所以是Object的方法就是因为任何一 ... 
- 关于java的wait、notify、notifyAll方法
		wait.notify.notifyAll 遇到的问题 之前开发打印机项目,因为需要使用多线程技术,当时并不怎么理解,一开始随意在方法体内使用wait.notify.notifyAll 方法导致出现了 ... 
- keepalived中vrrp_script,track_script,notify的使用方法
		keepalived中vrrp_script,track_script,notify的使用方法转自:https://blog.51cto.com/liuzhengwei521/1929589 可以在k ... 
- Java线程和多线程(十二)——线程池基础
		Java 线程池管理多个工作线程,其中包含了一个队列,包含着所有等待被执行的任务.开发者可以通过使用ThreadPoolExecutor来在Java中创建线程池. 线程池是Java中多线程的一个重要概 ... 
随机推荐
- 【数据结构(C语言版)系列三】 队列
			队列的定义 队列是一种先进先出的线性表,它只允许在表的一端进行插入,而在另一端删除元素.这和我们日常生活中的排队是一致的,最早进入队列的元素最早离开.在队列中,允许插入的一端叫做队尾(rear),允许 ... 
- Lucas+中国剩余定理 HDOJ 5446 Unknown Treasure
			题目传送门 题意:很裸,就是求C (n, m) % (p1 * p2 * p3 * .... * pk) 分析:首先n,m<= 1e18, 要用到Lucas定理求大组合数取模,当然p[]的乘积& ... 
- asp.net 微信登录实现方式
			之前我以为做微信登录跟微信公众号有关,后来发现是我想多了.原来微信还有一个叫开放平台的东西,见下图: 我的这个已经生成好了,没有的需要创建一个,https://open.weixin.qq.com/c ... 
- 关于ES6的Promise的使用深入理解
			ES6的promise对象研究 什么叫promise? Promise对象可以理解为一次执行的异步操作,使用promise对象之后可以使用一种链式调用的方式来组织代码:让代码更加的直观. 那我们为什么 ... 
- canvas绘制基础
			初始接口 <body> <canvas id=“canvas”></canvas> <script> var canvas = document.get ... 
- ssm框架搭建(下) 简单案例
			前言 这段时间没有更新博客,一直想做一个基于ssm的简单的项目.经过多次的尝试,终于实现了简单的增删查改功能了. 正文 由于前端的技术不是很熟悉,经过多方的查阅,使用了bootstrap的样式,来使界 ... 
- Javaweb学习笔记9—过滤器
			今天来讲javaweb的第9阶段学习. 过滤器,我在本次的思维导图中将过滤器和监听器放在一起总结了,监听器比较简单就不单独写了. 老规矩,首先先用一张思维导图来展现今天的博客内容. ... 
- 图解GitHub
			转自:http://marklodato.github.io/visual-git-guide/index-zh-cn.html 个人觉得这一篇比一些入门教程更值得看,图解很详细到位,很容易理解其工作 ... 
- Java  JDK装配置
			 1- 介绍 本文章介绍JAVA开发环境安装是基于: Java8(JDK8) 2- 下载JDK http://www.oracle.com/technetwork/java/javase/dow ... 
- 洛谷 P1030 求先序排列
			题目描述 给出一棵二叉树的中序与后序排列.求出它的先序排列.(约定树结点用不同的大写字母表示,长度<=8). 输入输出格式 输入格式: 2行,均为大写字母组成的字符串,表示一棵二叉树的中序与后序 ... 
