Java线程生命周期

类java.lang.Thread包含一个静态的State enum用于定义每种可能的状态. 在任意的时间点, 线程会处于以下的状态之一:

NEW – 新创建的线程, 还未启动(在调用 start() 之前的状态). A thread that has not yet started is in this state.
RUNNABLE – 正在运行或已经准备好运行但是在等待资源. either running or ready for execution but it’s waiting for resource allocation
BLOCKED – 在等待获取一个monitor lock来进入或重新进入同步的代码块或方法 waiting to acquire a monitor lock to enter or re-enter a synchronized block/method
WAITING – 在等待其他线程执行一个特定的操作, 没有时间限制 waiting for some other thread to perform a particular action without any time limit
由这三种方法之一进入 
object.wait()
thread.join()
LockSupport.park()

TIMED_WAITING – 在某个时间限制内, 等待其他线程执行一个特定的操作 waiting for some other thread to perform a specific action for a specified period
由这五种方法之一进入 
thread.sleep(long millis)
wait(int timeout) or wait(int timeout, int nanos)
thread.join(long millis)
LockSupport.parkNanos
LockSupport.parkUnti

TERMINATED – 运行已经结束或意外终止 has completed its execution

wait(), notify()和notifyAll()方法用于在线程间建立关联. 在对象上调用wait()将使线程进入WAITTING状态, 直到其他线程对同一个对象调用notify()或notifyAll(). 在任何线程上, 对一个对象调用wait(), notify()和notifyAll(), 都需要先获得这个对象的锁, 就是说, 这些方法必须在synchronized方法或代码块中调用.

wait()

在对象上调用wait(), 会使当前线程进入等待状态, 直至另一个线程对这个对象调用了notify() 或notifyAll() 方法. 换句话说, 就是简单的执行了wait(0)方法.

在调用wait()时, 当前线程必须拥有这个对象的monitor. 调用后, 线程会释放对象的monitor, 并一直等待直到另一个线程通过notify()或notifyAll()唤醒正在等待这个对象的monitor的线程们. 然后线程会一直等待直到重新拿回这个对象的monitor, 然后才能继续运行.

对于带参数的版本, 中断和唤醒都是可能的, 这个方法必须在一个循环中使用.

 synchronized (obj) {
while (<condition does not hold>)
obj.wait();
... // Perform action appropriate to condition
}

.

notify()

唤醒正在等待这个对象的monitor的线程中的一个. 如果有多个线程正在等待, 会选择其中的一个, 这个选择是任意的, 因具体实现而不同. 唤醒的线程并不会立即继续执行, 它需要获得这个对象的锁之后才能继续执行. 唤醒的对象将与其他正在竞争这个对象的锁的线程一起竞争对象的锁.

这个方法只允许在拥有当前对象的monitor的线程上调用, 一个线程要得到对象的monitor, 只能通过以下三种方法之一:

  • 执行这个对象的一个同步方法
  • 执行这个对象中的一段同步代码
  • 对于type类型的对象, 执行这个类的一个静态同步方法

在同一时刻, 只允许一个线程得到一个对象的monitor

调用notify()时, 在所有WAITING状态的线程中只会有一个线程被通知, 这个选择是随机的, 被通知的线程并不会立即得到对象的锁, 而是一直等到调用notify()的线程释放锁, 在这之前线程都是BLOCKED状态. 当获得锁后, 就会从BLOCKED状态变为RUNNING状态. 例子

class Shared {
synchronized void waitMethod() {
Thread t = Thread.currentThread();
System.out.println(t.getName() + " is releasing the lock and going to wait");
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(t.getName() + " has been notified and acquired the lock back");
} synchronized void notifyOneThread() {
Thread t = Thread.currentThread();
notify();
System.out.println(t.getName() + " has notified one thread waiting for this object lock");
}
} public class MainClass {
public static void main(String[] args) {
final Shared s = new Shared();
//Thread t1 will be waiting for lock of object 's'
Thread t1 = new Thread() {
@Override
public void run() {
s.waitMethod();
}
};
t1.start(); //Thread t2 will be waiting for lock of object 's'
Thread t2 = new Thread() {
@Override
public void run() {
s.waitMethod();
}
};
t2.start(); //Thread t3 will be waiting for lock of object 's'
Thread t3 = new Thread() {
@Override
public void run() {
s.waitMethod();
}
};
t3.start(); try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
} //Thread t4 will notify only one thread which is waiting for lock of object 's'
Thread t4 = new Thread() {
@Override
public void run() {
s.notifyOneThread();
}
};
t4.start();
}
}

.

notifyAll()

当线程在对象上调用notifyAll()时, 所有WAITING状态的线程都会被唤醒, 所有的线程都会从WAITING状态变成BLOCKED状态, 然后争抢对象的锁. 得到对象锁的线程, 将变成RUNNING状态, 而其他线程则继续保持BLOCKED状态继续等待获取对象锁. 例子

class Shared {
synchronized void waitMethod() {
Thread t = Thread.currentThread();
System.out.println(t.getName() + " is releasing the lock and going to wait");
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(t.getName() + " has been notified and acquired the lock back");
} synchronized void notifyAllThread() {
Thread t = Thread.currentThread();
notifyAll();
System.out.println(t.getName() + " has notified all threads waiting for this object lock");
}
} public class MainClass {
public static void main(String[] args) {
final Shared s = new Shared();
//Thread t1 will be waiting for lock of object 's'
Thread t1 = new Thread() {
@Override
public void run() {
s.waitMethod();
}
};
t1.start(); //Thread t2 will be waiting for lock of object 's'
Thread t2 = new Thread() {
@Override
public void run() {
s.waitMethod();
}
};
t2.start(); //Thread t3 will be waiting for lock of object 's'
Thread t3 = new Thread() {
@Override
public void run() {
s.waitMethod();
}
};
t3.start(); try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
} //Thread t4 will notify all threads which are waiting for lock of object 's'
Thread t4 = new Thread() {
@Override
public void run() {
s.notifyAllThread();
}
};
t4.start();
}
}

.

一个生产者和消费者的例子

注意, 在1个生产1个消费的情况下, 是能确保生产和消费的互相通知的, 但是在2个生产1个消费的情况下, 有可能要多次notify后消费线程才能拿到queue的锁.

public class DemoThreadWait1 {
Queue<Integer> queue = new LinkedList<>(); public void consume() {
synchronized (queue) {
while (queue.isEmpty()) {
try {
System.out.println("consume wait");
queue.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("remove all");
queue.clear();
queue.notify();
}
}
} public void produce(int i) {
synchronized (queue) {
if (queue.size() < 5) {
System.out.println("add " + i);
queue.add(i);
}
if (queue.size() >= 5) {
queue.notify();
try {
System.out.println("produce wait");
queue.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
} public static void main(String[] args) {
DemoThreadWait1 demo = new DemoThreadWait1();
new Thread(()->{
while(true) {
demo.consume();
}
}).start(); new Thread(()->{
while(true) {
demo.produce((int) (Math.random() * 1000));
}
}).start(); new Thread(()->{
while(true) {
demo.produce((int) (Math.random() * 1000));
}
}).start();
}
}

  

Java线程的wait(), notify()和notifyAll()的更多相关文章

  1. 线程:Java中wait、notify、notifyAll使用详解

    基础知识 首先我们需要知道,这几个都是Object对象的方法.换言之,Java中所有的对象都有这些方法. public final native void notify(); public final ...

  2. java线程学习之notify方法和notifyAll方法

    notify(通知)方法,会将等待队列中的一个线程取出.比如obj.notify();那么obj的等待队列中就会有一个线程选中并且唤醒,然后被唤醒的队列就会退出等待队列.活跃线程调用等待队列中的线程时 ...

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

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

  4. Java Thread wait、notify与notifyAll

    Java的Object类包含了三个final方法,允许线程就资源的锁定状态进行通信.这三个方法分别是:wait(),notify(),notifyAll(),今天来了解一下这三个方法.在任何对象上调用 ...

  5. 关于java的wait、notify、notifyAll方法

    wait.notify.notifyAll 遇到的问题 之前开发打印机项目,因为需要使用多线程技术,当时并不怎么理解,一开始随意在方法体内使用wait.notify.notifyAll 方法导致出现了 ...

  6. Java面试题之notify和notifyAll的区别

    锁池: 假设线程A已经拥有对象锁,线程B.C想要获取锁就会被阻塞,进入一个地方去等待锁的等待,这个地方就是该对象的锁池: 等待池: 假设线程A调用某个对象的wait方法,线程A就会释放该对象锁,同时线 ...

  7. java 关于wait,notify和notifyAll

    public synchronized void hurt() { //... this.wait(); //... } public synchronized void recover() { // ...

  8. java线程总结2--wait/notify(all)/sleep以及中断概念

    上一篇关于线程的博客简单梳理了一下多线程的一些基本概念,今天这篇博客再进行多线程编程中一些核心的方法进行简单的梳理和总结,主要是wait,sleep和notify方法以及中断的概念 一.中断概念. 在 ...

  9. Java线程与多线程教程

    本文由 ImportNew - liken 翻译自 Journaldev.   Java线程是执行某些任务的轻量级进程.Java通过Thread类提供多线程支持,应用可以创建并发执行的多个线程. 应用 ...

随机推荐

  1. Typora 基础的使用方法

    大标题:通过ctrl + 数字 1 2 3 ....方式,还可以通过加# 的方式 一级标题 二级标题 三级标题 最多可以有6个#号 序号标题: 有序缩进是1. + tab 回车之后自动生成下一个序号 ...

  2. synchronized的使用方法和作用域

    文章地址:https://mp.weixin.qq.com/s?__biz=MzI4NTEzMjc5Mw==&mid=2650554746&idx=1&sn=8e45e741c ...

  3. OpenStack核心组件-glance镜像服务

    1. glance介绍 Glance是Openstack项目中负责镜像管理的模块,其功能包括虚拟机镜像的查找.注册和检索等. Glance提供Restful API可以查询虚拟机镜像的metadata ...

  4. Centos7 yum安装postgresql 9.5

    添加RPM yum install https://download.postgresql.org/pub/repos/yum/9.5/redhat/rhel-7-x86_64/pgdg-centos ...

  5. python写入excel(方式二待完善)

    import xlsxwriter #创建一个工作簿并添加一张工作表,当然工作表是可以命名的# workbook = xlsxwriter.Workbook('Expenses01.xlsx')# w ...

  6. janusgraph-图数据库的学习(2)

    janusgraph的简单使用 当安装好以后简单的使用janusgraph 1.进入janusgraph的shell命令界面 [root@had214 janusgraph-0.3.1-hadoop2 ...

  7. tensorflow API _ 4 (Logging with tensorflow)

    TensorFlow用五个不同级别的日志信息.为了升序的严重性,他们是调试DEBUG,信息INFO,警告WARN,错误ERROR和致命FATAL的.当你配置日志记录在任何级别,TensorFlow将输 ...

  8. if语句的嵌套:从键盘输入3个实数,求其最大值。

    #include<stdio.h>void main(){ float a,b,c,max; scanf("%f%f%f",&a,&b,&c); ...

  9. 使用SpringBoot访问jsp页面

    1 编写application.yml文件 spring: mvc: view: suffix: .jsp prefix: /jsp/ 2 创建Controller层 @Controller @Req ...

  10. Linux 系统管理——服务器RAID及配置实战

    RAID称为廉价磁盘冗余阵列.RAID的基本想法是把多个便宜的小磁盘组合在一起.成为一个磁盘组,使性能达到或超过一个容量巨大.价格昂贵的磁盘. 2.级别介绍 RAID 0连续以位或字节为单位分割数据, ...