Java多线程中wait, notify and notifyAll的使用

本文为翻译文章,原文地址:http://www.journaldev.com/1037/java-thread-wait-notify-and-notifyall-example

在Java的Object类中有三个final的方法允许线程之间进行资源对象锁的通信,他们分别是: wait(), notify() and notifyAll()。

调用这些方法的当前线程必须拥有此对象监视器,否则将会报java.lang.IllegalMonitorStateException exception异常。

wait

Object的wait方法有三个重载方法,其中一个方法wait() 是无限期(一直)等待,直到其它线程调用notify或notifyAll方法唤醒当前的线程;另外两个方法wait(long timeout) 和wait(long timeout, int nanos)允许传入 当前线程在被唤醒之前需要等待的时间,timeout为毫秒数,nanos为纳秒数。

notify

notify方法只唤醒一个等待(对象的)线程并使该线程开始执行。所以如果有多个线程等待一个对象,这个方法只会唤醒其中一个线程,选择哪个线程取决于操作系统对多线程管理的实现。

notifyAll

notifyAll 会唤醒所有等待(对象的)线程,尽管哪一个线程将会第一个处理取决于操作系统的实现。

这些方法可以使用于“生产者-消费者”问题,消费者是在队列中等待对象的线程,生产者是在队列中释放对象并通知其他线程的线程。

让我们来看一个多线程作用于同一个对象的例子,我们使用wait, notify and notifyAll方法。


通过实例来理解

Message

一个java bean类,线程将会使用它并调用wait和notify方法。

Message.java

package com.journaldev.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方法以唤醒线程完成处理。注意等待线程必须通过加synchronized同步锁拥有Message对象的监视器。

Waiter.java

package com.journaldev.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对象的线程。注意synchronized代码块被用于持有Message对象的监视器。

Notifier.java

package com.journaldev.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();
        }

    }

}

WaitNotifyTest

一个测试类,交付创建多个等待线程和一个通过线程,并启动这些线程。

WaitNotifyTest.java

package com.journaldev.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()方法只能唤醒一个线程,另一个线程仍然在等待被唤醒。

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 Notifying work done

如果我们注释掉Notifier类中的notify() 方法的调用,并打开notifyAll() 方法的调用,将会有以下的输出信息。

notifyAll()

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 Notifying work done
waiter waiter thread got notified at time:1356318918120
waiter processed: notifier Notifying work done

一旦notifyAll()方法唤醒所有的Waiter线程,程序将会执行完成并退出。

时间: 2024-10-12 17:19:17

Java多线程中wait, notify and notifyAll的使用的相关文章

转 Java多线程中Sleep与Wait的区别

Java中的多线程是一种抢占式的机制,而不是分时机制.抢占式的机制是有多个线程处于可运行状态,但是只有一个线程在运行. 共同点: 1. 他们都是在多线程的环境下,都可以在程序的调用处阻塞指定的毫秒数,并返回. 2. wait()和sleep()都可以通过interrupt()方法 打断线程的暂停状态 ,从而使线程立刻抛出InterruptedException. 如果线程A希望立即结束线程B,则可以对线程B对应的Thread实例调用interrupt方法.如果此刻线程B正在wait/sleep/

thread.join函数,java多线程中的join函数解析

join函数的作用,是让当前线程等待,直到调用join()的 线程结束或者等到一段时间,我们来看以下代码 1 package mian; 2 3 4 public class simpleplela { 5 static void threadMessage(String message) { 6 String threadName = 7 Thread.currentThread().getName(); 8 9 System.out.println(threadName+" "+m

java多线程中join用法

thread.Join把指定的线程加入到当前线程,可以将两个交替执行的线程合并为顺序执行的线程.比如在线程B中调用了线程A的Join()方法,直到线程A执行完毕后,才会继续执行线程B. package com.wzs; /** * Java多线程中join用法 * * @author Administrator * */ public class JoinTest { public static void main(String[] args) { BThread bThread = new B

Java多线程中的死锁问题[转]

//申明:本文转载自http://www.cnblogs.com/digdeep/p/4448148.html <Java多线程中的死锁问题> Java程序基本都要涉及到多线程,而在多线程环境中不可避免的要遇到线程死锁的问题.Java不像数据库那么能够检测到死锁,然后进行处理,Java中的死锁问题,只能通过程序员自己写代码时避免引入死锁的可能性来解决. 1. Java中导致死锁的原因 Java中死锁最简单的情况是,一个线程T1持有锁L1并且申请获得锁L2,而另一个线程T2持有锁L2并且申请获得

Java多线程中的竞争条件、锁以及同步的概念

竞争条件 1.竞争条件: 在java多线程中,当两个或以上的线程对同一个数据进行操作的时候,可能会产生"竞争条件"的现象.这种现象产生的根本原因是因为多个线程在对同一个数据进行操作,此时对该数据的操作是非"原子化"的,可能前一个线程对数据的操作还没有结束,后一个线程又开始对同样的数据开始进行操作,这就可能会造成数据结果的变化未知. package com.huojg.test; public class TestThread { public static void

Java多线程中的Runnable和Thread

摘要: 在java中可有两种方式实现多线程,一种是继承Thread类,一种是实现Runnable接口:Thread类是在java.lang包中定义的.一个类只要继承了Thread类同时覆写了本类中的run()方法就可以实现多线程操作了,但是一个类只能继承一个父类,这是此方法的局限. 用法: Thread: package org.thread.demo;class MyThread extends Thread{ private String name; public MyThread(Stri

java 多线程中的 wait 和 notify

wait和notify是通过对对象进行锁,来实现同步和互斥. wait和notify函数需要在一段的同步代码中,即在 synchronized的代码段中. 简单的示例代码. static class TestThread { public Boolean locked = false; public void run() { long last = System.currentTimeMillis(); synchronized (locked) { while (locked) { // 释放

Java多线程中Sleep与Wait的区别

Java中的多线程是一种抢占式的机制,而不是分时机制.抢占式的机制是有多个线程处于可运行状态,但是只有一个线程在运行. 共同点: 1. 他们都是在多线程的环境下,都可以在程序的调用处阻塞指定的毫秒数,并返回. 2. wait()和sleep()都可以通过interrupt()方法 打断线程的暂停状态 ,从而使线程立刻抛出InterruptedException. 如果线程A希望立即结束线程B,则可以对线程B对应的Thread实例调用interrupt方法.如果此刻线程B正在wait/sleep/

Java多线程中join、yield、sleep方法详解

在Java多线程编程中,Thread类是其中一个核心和关键的角色.因此,对该类中一些基础常用方法的理解和熟练使用是开发多线程代码的基础.本篇主要总结一下Thread中常用的一些静态方法的含义及代码中的使用. sleep方法 源码如下: /** * Causes the currently executing thread to sleep (temporarily cease * execution) for the specified number of milliseconds, subje