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. python私有工具库小结

    1.一些试用py工具清单 https://www.zhihu.com/question/60402355/answer/752917744?utm_source=wechat_session& ...

  2. MySQL DDL--MySQL 5.7版本Online DDL操作

    主键索引维护 1.新增主键索引 ## 可以使用ALGORITHM=INPLACE+LOCK=NONE方式,操作期间允许读写. ALTER TABLE tb001 ADD PRIMARY KEY (ID ...

  3. JS正则表达式提取数字

    /** * [参数str] * @type {var String} * return 30 */ var str = "ren民BI30kuai" console.log(str ...

  4. 基于CentOS7配置ArcGIS enterprise

    Centos7GUI安装过程 1.右键点击列表中的虚拟主机,打开控制台. 点击绿色开机键,开始安装. 这里有一个很关键的点,就是上一步设置中的打开电源自动连接.一开始设置的时候别忘了. 2.开机后会出 ...

  5. KClass与函数引用详解

    继续学习Kotlin反射相关的东东. KClass: 在上一次是通过类来获取它的KClass对象: 那如果是一个对象呢?与这个对象对应的类的KClass对象又是如何获取的呢?像Java也是一样有相关机 ...

  6. 史上最完整promise源码手写实现

    史上最完整的promise源码实现,哈哈,之所以用这个标题,是因为开始用的标题<手写promise源码>不被收录 promise自我介绍 promise : "君子一诺千金,承诺 ...

  7. Python获取当前脚本文件夹(Script)的绝对路径

    Python获取当前脚本绝对路径 Python脚本有一个毛病,当使用相对路径时,被另一个不同目录下的py文件中导入时,会报找不到对应文件的问题.感觉是当前工作目录变成了导入py文件当前目录.如果你有配 ...

  8. P4139 上帝与集合的正确用法[欧拉定理]

    题目描述 求 \[ 2^{2^{2\cdots}} ~mod ~p \] 简单题,指数循环节. 由于当\(b>=\psi(p)\)时,有 \[ a^b=a^{b ~mod~\psi(p)+\ps ...

  9. datebox设置默认时间

    1. html代码: <input id="txtBeginTime" class="easyui-datebox" data-options=" ...

  10. html5添加视频为背景自动播放

    客户想做个打开官网自动播放一段视频,楼主使用了video标签,即下面的代码:: 于是我在video标签上添加了属性 autoplay=“autoplay” loop=“loop” 然而通过地址栏进去的 ...