Java 多线程学习笔记:wait、notify、notifyAll的阻塞和恢复

前言:昨天尝试用Java自行实现生产者消费者问题(Producer-Consumer Problem),在coding时,使用到了Condition的await和signalAll方法,然后顺便想起了wait和notify,在开发中遇到了一个问题:wait、notify等阻塞和恢复的时机分别是什么?在网上Google了很久各种博文后,发现几乎没有人提到这个点。最后在官方文档中才找到了相应的介绍。

(一)准备

  按照惯例应该是要先介绍一下wait、notify和notifyAll的基础知识。我找到了一篇不错的文章:《Java的wait(), notify()和notifyAll()使用小结》,它甚至介绍了为什么wait等方法为什么必须先获得对象锁。在这里我就不重复说了。

(二)阻塞和恢复

(1)wait方法

  wait方法继承自Object类(方法修饰符为fianl native,这也解释了为什么condition类中不能重写wait等方法),一共有三个方法:

public final void wait(long timeout)
                throws InterruptedException

public final void wait(long timeout, int nanos)
                throws InterruptedException

public final void wait()
                throws InterruptedException

  阻塞:这三个方法的调用都会使当前线程阻塞。该线程将会被放置到对该Object的请求等待队列中,然后让出当前对Object所拥有的所有的同步请求。线程会一直暂停所有线程调度,直到下面其中一种情况发生:

    ① 其他线程调用了该Object的notify方法,而该线程刚好是那个被唤醒的线程;

    ② 其他线程调用了该Object的notifyAll方法;

    ③ 其他对象中断/杀死了该线程;

    ④ (这种情况,只针对前两个方法)线程在等待指定的时间后;

  恢复:线程将会从等待队列中移除,重新成为可调度线程。它会与其他线程以常规的方式竞争对象同步请求。一旦它重新获得对象的同步请求,所有之前的请求状态都会恢复,也就是线程调用wait的地方的状态。线程将会在之前调用wait的地方继续运行下去。

(2)notify和notifyAll方法

  notify的作用就是唤醒请求队列中的一个线程,而notifyAll唤醒的是请求队列中的所有线程。

  被唤醒的线程不会马上运行,除非获取了该Object的锁。也就是说,调用notify的线程,在调用notify后,不会像wait一样,马上阻塞线程的运行。而是继续运行,直到相应的线程调度完成或者让出Object的锁。而被唤醒的线程会在当前线程让出Object锁后,与其他线程以常规的方式竞争对象锁(正如上面提到的)。

参考资料:

https://docs.oracle.com/javase/7/docs/api/java/lang/Object.html

时间: 2024-08-25 06:22:48

Java 多线程学习笔记:wait、notify、notifyAll的阻塞和恢复的相关文章

Java多线程学习笔记--生产消费者模式

实际开发中,我们经常会接触到生产消费者模型,如:Android的Looper相应handler处理UI操作,Socket通信的响应过程.数据缓冲区在文件读写应用等.强大的模型框架,鉴于本人水平有限目前水平只能膜拜,本次只能算学习笔记,为了巩固自己对Java多线程常规知识点的理解,路过大神还望能指导指导.下面一段代码是最常规的生产者消费者的例子: package com.zhanglei.demo; import java.util.ArrayList; import java.util.List

Java 多线程学习笔记:生产者消费者问题

前言:最近在学习Java多线程,看到ImportNew网上有网友翻译的一篇文章<阻塞队列实现生产者消费者模式>.在文中,使用的是Java的concurrent包中的阻塞队列来实现.在看完后,自行实现阻塞队列. (一)准备 在多线程中,生产者-消费者问题是一个经典的多线程同步问题.简单来说就是有两种线程(在这里也可以做进程理解)——生产者和消费者,他们共享一个固定大小的缓存区(如一个队列).生产者负责产生放入新数据,消费者负责取出缓存区的数据.具体介绍请参考 Producer-consumer

Java多线程学习笔记(一)

一 概述 一个进程只有一个至少会运行一个线程,Java中同样存在这样,在调用main方法的时候,线程又JVM所创建. 1 package link.summer7c.test; 2 3 public class Test{ 4 public static void main(String[] args){ 5 System.out.println(Thread.currentThread().getName()); 6 } 7 } 运行结果:main 叫做main的线程正在执行main()方法中

Java多线程学习笔记——从Java JVM对多线程数据同步的一些理解

   我们知道在多线程编程中,我们很大的一部分内容是为了解决线程间的资源同步问题和线程间共同协作解决问题.线程间的同步,通俗我们理解为僧多粥少,在粥有限情况下,我们怎么去防止大家有秩序的喝到粥,不至于哄抢都没得喝.线程讲协作,我们可以理解为我们在医院看病的时候,我们要先挂号,才能看病.现在医院有很多病人排队,怎么协调病人都有秩序的先挂号,后看病.本篇文章的重点不在此,也不是在此一下子能分析完,我们先从Java JVM的角度来理解多线程的一些方面. 我们知道多线程间的数据同步,我们是通过加锁的操作

java多线程学习笔记——简单

进程:程序(任务)的执行过程——动态性. 持有资源(共享内存,共享文件)和线程. 线程:线程是系统中最小的执行单元,统一进程中有多个线程,线程共享进程的资源. 线程交互:互斥与同步. 注意:多线程是异步的,所以千万不要把Eclipse里代码的顺序当成线程执行的顺序,线程被调用的时机是随机的. java对线程的支持: class Thread    interface Runnable    共同的run方法 线程的创建和启动: 线程常用方法: 如何停止线程: java中有三种方法可以终止正在运行

Java多线程学习笔记1

1.线程的基本概念 一个关于计算机的简化的视图是: 它有一个执行计算的处理机. 包含处理机所执行的程 序的 ROM(只读存储器). 包含程序所要操作的数据的 RAM(只读存储器).线程,被认为是带有自己的程 序代码和数据的拟处理机的封装.线程的三个部分处理机,代码,数据. 代码可以或不可以由多个线程共享, 这和数据是独立的. 两个线程如果执行同一个类的 实例代码,则它们可以共享相同的代码. 类似地,数据可以或不可以由多个线程共享, 这和代码是独立的. 两个线程如果共享对 一个公共对象的存取,则它

Java多线程学习笔记——信号量的使用

Java中在控制多线程访问资源的时候使用了信号量可以控制多个线程同时访问一个资源. 有两个构造方法: public Semaphore(int permits) public Semaphore(int permits,boolean fair) 第二个参数和重入锁一样,是指定是否公平.(公平是要牺牲性能的) 1 public class SignalNum implements Runnable { 2 Semaphore semaphore=new Semaphore(2); 3 4 5 @

java 多线程学习笔记(一) -- 计算密集型任务

最近在看<Java虚拟机并发编程>,在此记录一些重要的东东. 线程数的确定:1. 获取系统可用的处理器核心数:int numOfCores = Runtime.getRuntime().availableProcessors()2. 如果任务是计算密集型的,则线程数 = numOfCores        如果任务是IO密集型的,则线程数 = numOfCores / (1 - 阻塞系数), 其中阻塞系数在0~1之间.注:如果任务被阻塞的时间大于执行时间, 则这些任务是IO密集型的,我们就需要

java多线程学习笔记

一.线程的创建 1.  通过继承Thread类,重写Thread的run()方法,将线程运行的逻辑放在其中 2.  通过实现Runnable接口,实例化Thread类 但是在使用Runnable定义的子类中没有start()方法,只有Thread类中才有.此时观察Thread类,有一个构造方法:public Thread(Runnable targer)此构造方法接受Runnable的子类实例,也就是说可以通过Thread类来启动Runnable实现的多线程.(start()可以协调系统的资源)