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. Pod和Namespace的基本介绍

    namespace资源名称空间 删除namespace资源会级联删除其所包含的所有其它资源对象    名称空间仅仅只是用来限制资源名称的作用域      并不能实现Pod的通信隔离 在名称空间下操作s ...

  2. Linq 等式运算符:SequenceEqual(转载)

    https://www.bbsmax.com/A/nAJvbKywJr/ 引用类型比较的是引用,需要自己实现IEqualityComparer 比较器. IList<string> str ...

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

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

  4. Spring @Cacheable注解 && 事务@Transactional 在同一个类中的方法调用不生效

    @Cacheable 注解在对象内部调用不会生效 代码示例:ProductServiceImpl.java public List<ProductInfoVO> getProductLis ...

  5. mysql的innodb数据存储结构

    ​ 数据库磁盘读取与系统磁盘读取 1,系统从磁盘中读取数据到内存时是以磁盘块(block)为基本单位,位于同一个磁盘块中的数据会被一次性读取出来. 2,innodb存储引擎中有页(Page)的概念,页 ...

  6. vue-i18n安装和实现国际化,$t的用法

    1.安装 yarn install vue-i18n 也可以直接引入 <script src="https://unpkg.com/vue/dist/vue.js">& ...

  7. Windows 将FTP 映射到本地文件夹 --简化操作

    转载自yutiantongbu Windows 将FTP 映射到本地文件夹 --简化操作 1.右键我的电脑,选择映射网络驱动器 2.选择"连接到可用与存储文档和图片的网站" 3.接 ...

  8. mac 使用 brew 安装 nginx 及各种命令

    一.安装 brew install nginx 或 sudo brew install nginx 二.启动 brew services start nginx 或 sudo brew service ...

  9. HBase的二级索引

    使用HBase存储中国好声音数据的案例,业务描述如下: 为了能高效的查询到我们需要的数据,我们在RowKey的设计上下了不少功夫,因为过滤RowKey或者根据RowKey查询数据的效率是最高的,我们的 ...

  10. Sql语句中Like嵌套用法

    一般的Like用法: SELECT U_NAME FROM T_USER WHERE U_NAME LIKE '%A%' 但是,我此次like关键字后面的对应值是一个变量,需要用select语句来实现 ...