博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
第三章-线程间的通信-第一篇
阅读量:6567 次
发布时间:2019-06-24

本文共 6929 字,大约阅读时间需要 23 分钟。

hot3.png

等待通知机制

等待通知机制的实现

方法wait()的作用是使当前执行代码的线程进行等待,wait方法是object类的方法,作用就是使当前的线程进入预执行队列中,并且在wait方法所在的代码块处停止执行,直到接到通知或者中断位置。在调用wait之前,线程必须获得对象级别的锁,即只能在同步方法或者同步代码块中调用wait方法。

当前线程执行完wait方法后,当前线程会释放掉对象锁,在wait方法返回之前,线程和其他线程竞争重新获得锁。

唤醒线程采用notify方法,该方法用来通知哪些可能等待该对象的对象锁的其他线程,如果有多个线程等待,则有线程规划器随机挑出一个呈wait状态的线程,对其发出通知notify。 需要知道的是当线程发出notify通知以后当前线程不会马上释放锁该对象锁,呈现wait状态的线程也不能马上获得该对象锁,需要等待notify方法的线程执行完以后才能获得该对象锁。

wait的一个线程获得锁以后,会释放掉当前线程的锁,此时如果没有对象再次使用notify语句,则即便该对象已经空闲,其他wait状态等待的线程由于没有接到该对象的通知,还会继续阻塞在wait状态,直到这个对象发出notify或者notifyall通知。

请看如下程序:

public class MainRun {    public static void main(String[] args) {        String string = new String("");        try {            string.wait();        } catch (InterruptedException e) {            e.printStackTrace();        }    }}

输出如下

Exception in thread "main" java.lang.IllegalMonitorStateException	at java.lang.Object.wait(Native Method)	at java.lang.Object.wait(Object.java:503)	at chaprer3.MainRun.main(MainRun.java:19)	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)	at java.lang.reflect.Method.invoke(Method.java:606)	at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)

出现异常的原因就是没有给对象加锁,也就是没有同步加锁器,必须是对象级别的锁(不明白参考第二章)。

wait和notify使用实例:

public class PublicObject {}public class ThreadA extends Thread {    private PublicObject object;    public ThreadA(PublicObject object) {        this.object = object;    }    @Override    synchronized public void run() {        synchronized (this.object) {            System.out.println("TheadTest1将要进行wait方法了");            try {                this.object.wait();				System.out.println("之前就已经释放锁了,我现在只有重新得到锁才可以运行");            } catch (InterruptedException e) {                e.printStackTrace();            }            System.out.println("TheadTest1将要结束了");        }    }}public class ThreadB extends Thread {    private PublicObject object;    public ThreadB(PublicObject object) {        this.object = object;    }    @Override    public void run() {        synchronized (this.object) {            System.out.println("我将要发出通知了");            this.object.notify();			System.out.println("我就是不马上释放锁,我要把这个代码块运行完才释放");            System.out.println("通知结束了");        }    }}    public class MainRun {    public static void main(String[] args) throws InterruptedException {        PublicObject object = new PublicObject();        ThreadA threadA = new ThreadA(object);        threadA.start();        Thread.sleep(2000);        ThreadB threadB = new ThreadB(object);        threadB.start();    }}

输出结果

TheadTest1将要进行wait方法了我将要发出通知了我就是不马上释放锁,我要把这个代码块运行完才释放通知结束了之前就已经释放锁了,我现在只有重新得到锁才可以运行TheadTest1将要结束了

interupt方法遇到wait方法。

当线程呈现wait状态的时候,调用线程对象的interrupt方法会出现interruptedException异常。

public class ThreadA extends Thread {    private PublicObject object;    public ThreadA(PublicObject object) {        this.object = object;    }    @Override    synchronized public void run() {        synchronized (this.object) {            System.out.println("TheadTest1将要进行wait方法了");            try {                this.object.wait();            } catch (InterruptedException e) {                e.printStackTrace();                System.out.println("出现异常了,因为wait方法被interrupt了!");            }        }    }}public class MainRun {    public static void main(String[] args) throws InterruptedException {        PublicObject object = new PublicObject();        ThreadA threadA = new ThreadA(object);        threadA.start();        Thread.sleep(2000);        threadA.interrupt();    }}

输出结果

TheadTest1将要进行wait方法了java.lang.InterruptedException	at java.lang.Object.wait(Native Method)	at java.lang.Object.wait(Object.java:503)	at chaprer3.ThreadA.run(ThreadA.java:21)出现异常了,因为wait方法被interrupt了!

notify方法只通知一个线程

notify方法只随机通知一个线程进行唤醒。

public class PublicObject {}public class ThreadA extends Thread {    private PublicObject object;    public ThreadA(PublicObject object) {        this.object = object;    }    @Override    synchronized public void run() {        synchronized (this.object) {            try {                System.out.println("开始等待"+Thread.currentThread().getName());                this.object.wait();                System.out.println("已经唤醒"+Thread.currentThread().getName());            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }}public class ThreadB extends Thread {    private PublicObject object;    public ThreadB(PublicObject object) {        this.object = object;    }    @Override    public void run() {        synchronized (this.object) {            System.out.println("唤醒触发一次");            this.object.notify();        }    }}    public class MainRun {    public static void main(String[] args) throws InterruptedException {        PublicObject object = new PublicObject();        ThreadA threadA1 = new ThreadA(object);        threadA1.start();        ThreadA threadA2 = new ThreadA(object);        threadA2.start();        ThreadA threadA3 = new ThreadA(object);        threadA3.start();        Thread.sleep(1000);        ThreadB threadB = new ThreadB(object);        threadB.start();        ThreadB threadB1 = new ThreadB(object);        threadB1.start();        ThreadB threadB3 = new ThreadB(object);        threadB3.start();        ThreadB threadB4 = new ThreadB(object);        threadB4.start();        ThreadB threadB5 = new ThreadB(object);        threadB5.start();    }}

输出结果

开始等待Thread-0开始等待Thread-1开始等待Thread-2唤醒触发一次已经唤醒Thread-0唤醒触发一次已经唤醒Thread-1唤醒触发一次已经唤醒Thread-2唤醒触发一次唤醒触发一次

程序多次使用notify来唤醒线程,但是如果有非常多的线程的时候就很难保证所有的线程都被唤醒了。

唤醒所有线程

当notify调用的次数小于线程对象的数量的时候,会出现部分线程无法被唤醒的情况,为了唤醒全部的线程,可以使用notifyAll方法,稍微修改线程B的代码

public class ThreadB extends Thread {    private PublicObject object;    public ThreadB(PublicObject object) {        this.object = object;    }    @Override    public void run() {        synchronized (this.object) {            System.out.println("唤醒所有线程触发一次");            this.object.notifyAll();        }    }}

输出结果

开始等待Thread-0开始等待Thread-2开始等待Thread-1唤醒所有线程触发一次已经唤醒Thread-1已经唤醒Thread-2已经唤醒Thread-0

自动唤醒线程

带一个参数的wait(long)方法的功能就是等待某一时间类是否有线程对对象进行唤醒,如果超过这个时间则自动唤醒,稍微修改一下程序的代码

public class ThreadA extends Thread {    private PublicObject object;    public ThreadA(PublicObject object) {        this.object = object;    }    @Override    synchronized public void run() {        synchronized (this.object) {            try {                System.out.println("开始等待"+Thread.currentThread().getName());                this.object.wait(1000);                System.out.println("已经唤醒"+Thread.currentThread().getName());            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }}

输出结果

开始等待Thread-0开始等待Thread-1开始等待Thread-2已经唤醒Thread-0已经唤醒Thread-1已经唤醒Thread-2唤醒所有线程触发一次

转载于:https://my.oschina.net/jiansin/blog/1934865

你可能感兴趣的文章
数据预处理代码分享——机器学习与数据挖掘
查看>>
python实现客户端和服务器端传输图片
查看>>
Web3.js 0.20.x API 中文版翻译
查看>>
前端每日实战:143# 视频演示如何用 CSS 的 Grid 布局创作一枚小松鼠邮票
查看>>
phpstorm 关闭多余变量提示
查看>>
DOM概述 选取文档元素
查看>>
构建你的第一个Vue.js组件
查看>>
如何完整迁移git仓库到另一个远程地址
查看>>
autocad三维汇报,bim汇报,视图汇报方法
查看>>
来来来,你可能没见过这么全的实战吧
查看>>
【队列源码研究】消息队列beanstalkd源码详解
查看>>
JS基础知识学习(一)
查看>>
多条语音消息合成一整条连续播放与进度条功能技术点!
查看>>
最详细的JavaWeb开发基础之java环境搭建(Windows版)
查看>>
通过btrace排查线上频繁Full GC的case
查看>>
JS基础入门篇(一)
查看>>
JavaScript-包装对象
查看>>
SpringBoot+Mybatis配置Druid多数据源
查看>>
从事GIS开发多年,2017年对GIS行业的心得,尤其对三维GIS的理解
查看>>
golang中数组和slice作为参数的区别
查看>>