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. day 04作业

    目录 简述Python的五大数据类型的作用.定义方式.使用方法: 数字类型 字符串类型(str) 列表(list) 字典(dict) 布尔型(bool) 一行代码实现下述代码实现的功能: 写出两种交换 ...

  2. Gitlab创建一个项目

    1.安装git yum install git 2.生成密钥文件:使用ssh-keygen生成密钥文件.ssh/id_rsa.pub ssh-keygen 执行过程中输入密码,以及确认密码,并可设置密 ...

  3. MySQL/MariaDB数据库的复制加密

      MySQL/MariaDB数据库的复制加密 作者:尹正杰  版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.MySQL的安全问题 1>.基于SSL复制 在默认的主从复制过程或远程连接 ...

  4. yaml模块

    原文链接:https://www.cnblogs.com/fancyl/p/9133738.html 一.安装yaml模块:pip install pyyaml 二.在pycharm里新建.yaml文 ...

  5. gcc的__builtin_函数(注意前面是两个下划线)

    说明: GCC provides a large number of built-in functions other than the ones mentioned above. Some of t ...

  6. Linux查看文件指定行数内容

    1.tail date.log               输出文件末尾的内容,默认10行 tail -20  date.log        输出最后20行的内容 tail -n -20  date ...

  7. 从url中下载资源(目前测试只有照片,文件类的没有进行测试)

    首先:是工具类: public class DownLoadUtils { /** * 从网络Url中下载文件 * * @param urlStr url路径 * @param fileName 文件 ...

  8. Java内存区域与内存溢出异常(jdk 6,7,8)

    运行时数据区域 Java虚拟机在执行Java程序的过程中会把它关联的内存划分为若干个不同的数据区域.这些区域都有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有些区域则依赖用户 ...

  9. django-导入应用包的搜索路径

    创建应用包 在 settings.py注册和配置urls.py中要按顺序导入包名和应用名 settings.py INSTALLED_APPS = ( 'django.contrib.admin', ...

  10. 对于模块加载:ES6、CommonJS、AMD、CMD的区别

    运行和编译的概念 编译包括编译和链接两步. 编译,把源代码翻译成机器能识别的代码或者某个中间状态的语言. 比如java只有JVM识别的字节码,C#中只有CLR能识别的MSIL.还简单的作一些比如检查有 ...