Java基础笔记 – 线程间通信的实现 wait()和notify()方法
本文由发表于6年前 | Java基础 | 评论数 1 |  被围观 13,481 views+
线程间的通信:死锁(deadlock):Object类中的两个方法:下面通过这两个方法实现线程间的通信:关于wait和notify两个方法的说明:wait方法与sleep方法的区别:以下是加入线程间通信和对象锁后的线程状态图:
线程间的通信:

Java提供了3个非常重要的方法来巧妙地解决线程间的通信问题。这3个方法分别是:wait()、notify()和notifyAll()。它们都是Object类的最终方法,因此每一个类都默认拥有它们。

虽然所有的类都默认拥有这3个方法,但是只有在synchronized关键字作用的范围内,并且是同一个同步问题中搭配使用这3个方法时才有实际的意义。

死锁(deadlock):

所谓死锁,是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。 由于资源占用是互斥的,当某个进程提出申请资源后,使得有关进程在无外力协助下,永远分配不到必需的资源而无法继续运行,这就产生了一种特殊现象死锁。

Object类中的两个方法:
wait
public final void wait(long timeout)
                throws InterruptedException
在其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量前,导致当前线程等待。
当前线程必须拥有此对象监视器(对象锁),即调用的wait方法一定在synchronized代码块或方法里面。
此方法导致当前线程(称之为 T)将其自身放置在对象的等待集中,然后放弃此对象上的所有同步要求。出于线程调度目的,在发生以下四种情况之一前,线程 T 被禁用,且处于休眠状态:
•	其他某个线程调用此对象的 notify 方法,并且线程 T 碰巧被任选为被唤醒的线程。
•	其他某个线程调用此对象的 notifyAll 方法。
•	其他某个线程中断线程 T。
•	大约已经到达指定的实际时间。但是,如果 timeout 为零,则不考虑实际时间,在获得通知前该线程将一直等待。

然后,从对象的等待集中删除线程 T,并重新进行线程调度。然后,该线程以常规方式与其他线程竞争,以获得在该对象上同步的权利;一旦获得对该对象的控制权,该对象上的所有其同步声明都将被恢复到以前的状态,这就是调用 wait 方法时的情况。然后,线程 T 从 wait 方法的调用中返回。所以,从 wait 方法返回时,该对象和线程 T 的同步状态与调用 wait 方法时的情况完全相同。

notify
public final void notify()
唤醒在此对象监视器(对象锁)上等待的单个线程。如果所有线程都在此对象上等待,则会选择唤醒其中一个线程。选择是任意性的,并在对实现做出决定时发生。线程通过调用其中一个 wait 方法,在对象的监视器上等待。
直到当前线程放弃此对象上的锁定,才能继续执行被唤醒的线程。被唤醒的线程将以常规方式与在该对象上主动同步的其他所有线程进行竞争;例如,唤醒的线程在作为锁定此对象的下一个线程方面没有可靠的特权或劣势。
此方法只应由作为此对象监视器(对象锁)的所有者的线程来调用。通过以下三种方法之一,线程可以成为此对象监视器的所有者:
•	通过执行此对象的同步实例方法。
•	通过执行在此对象上进行同步的 synchronized 语句的正文。
•	对于 Class 类型的对象,可以通过执行该类的同步静态方法。

一次只能有一个线程拥有对象的监视器(对象锁)。

下面通过这两个方法实现线程间的通信:

首先创建一个Number2类,该类有一个add方法和一个sub synchronized方法:

class Number2 {

    private int number;
    //增加数量的synchronized方法
    public synchronized void add(){
        //注意,这里不用if,因为如果有多个线程随意唤醒
        //下下一次随意唤醒线程时,可能就不会再作判断了,从而使判断失效
        while(0!=number){
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        number++;
        System.out.println(number);
        notify();
    }
    //减少数量的synchronized方法
    public synchronized void sub(){
        while(0 == number){
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        number--;
        System.out.println(number);
        notify();
    }
}

然后是调用add方法对应的线程类:

class AddThread extends Thread{
    private Number2 number;

    public AddThread(Number2 number){
        this.number = number;
    }
    @Override
    public void run() {
        for(int i = 0; i<10; i++){
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            number.add();
        }
    }
}

接下来是调用sub方法对应的线程类:

class SubThread extends Thread{
    private Number2 number;

    public SubThread(Number2 number){
        this.number = number;
    }
    @Override
    public void run() {
        for(int i = 0; i<10; i++){
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            number.sub();
        }
    }
}

在main方法中创建多个线程同时执行:

public static void main(String[] args) {
    Number2 number = new Number2();
    AddThread addThread = new AddThread(number);
    SubThread subThread = new SubThread(number);
    AddThread addThread2 = new AddThread(number);
    SubThread subThread2 = new SubThread(number);
    addThread.start();
    subThread.start();
    addThread2.start();
    subThread2.start();
}

发现控制台只循环输出0和1。

关于wait和notify两个方法的说明:

两个方法都是定义在Object类中的final方法,因此所有的Java类都拥有此方法并且无法重写。

调用这两个方法之前要求线程获得对象的锁,即是对这两个方法的调用需要方法在synchronized方法或同步代码块中。

线程执行了wait方法时,线程进入等待,并释放掉对象锁。

wait方法与sleep方法的区别:

sleep方法只是让线程休眠了设置好的时间,但并不会释放获得的对象锁。而wait方法则会释放掉对象锁。

以下是加入线程间通信和对象锁后的线程状态图:

除了文章中有特别说明,均为IT宅原创文章,转载请以链接形式注明出处。
本文链接:http://www.itzhai.com/java-based-notebook-the-realization-of-communication-between-threads-wait-and-notify-method.html
关键字: , , ,
arthinking Java技术交流群:280755654,入门群:428693174 more
分享到:
 
2011 10/25
文章评论
    一条评论
给我留言

有人回复时邮件通知我
Java基础的相关文章
随机文章 本月热门 热评
1 Java笔记 – toString方法 无意识的递归 2013/12/13
2 Eclipse下搭建Python开发环境 2014/2/28
3 Hibernate一对一唯一外键关联映射的实现方法实例 2011/9/4
4 ExtJS的FormPanel中的组件使用load加载远程的JSON数据的方法 2011/8/6
5 Ubuntu安装方案 超炫界面 VirtualBox让你从windows到Linux适应的完美过渡 2011/5/2
6 需要有的一种热血职人精神 2013/12/27
友情推荐 更多
破博客 文官洗碗安天下,武将打怪定乾坤。多么美好的年代,思之令人泪落。
Mr.5's Life 白天是一名程序员,晚上就是个有抱负的探索者
行知-追寻技术之美 关注大数据,分布式系统
我爱编程 编程成长轨迹
Cynthia's Blog 学习笔记 知识总结 思考感悟
 
猜您喜欢
欢迎关注我的公众号 IT宅
关于IT宅 文章归档

IT宅中的文章除了标题注明转载或有特别说明的文章,均为IT宅的技术知识总结,学习笔记或随笔。如果喜欢,请使用文章下面提供的分享组件。转载请注明出处并加入文章的原链接。 感谢大家的支持。

联系我们:admin@itzhai.com

Theme by arthinking. Copyright © 2011-2015 IT宅.com 保留所有权利.