线程的挂起和唤醒

简介: 线程的挂起和唤醒

公众号merlinsea


线程的状态转换流程



   NEW 新建态:线程一旦创建及处于这个状态

   Runnable运行态,可以被JVM执行的状态

   blocked阻塞态:通常是没有获取锁资源所处于的状态

   waiting等待态:某个线程显示调用自己所获取锁的wait方法,如果没有其他线程唤醒,那么将一直得不到调度

   time waiting 超时等待态:某个线程显示调用自己所获取锁的wait方法并指定最大等待时间,如果超出最大等待时间没有被唤醒将自动被唤醒

   terminated终止态:线程执行完毕

640.jpg


obj.wait():在某个线程中调用该方法,表示该线程进入挂起等待状态,后续代码暂停执行,只有被其他线程唤醒以后才能执行,并且释放持有的锁!!

obj.notify():随机唤醒挂起在obj对象上的【一个】等待线程

obj.notifyAll():唤醒挂起在obj对象上的【所有】等待线程


注意点:

1、调用wait()和notify()方法的线程必须是持有锁的线程

2、当前线程持有的锁和调用wait和notify方法的对象obj必须是同一个对象

3、线程调用wait方法挂起以后会释放自己持有的锁


public class WaitDemo implements Runnable {
    private static Object waitObj = new Object();
    @Override
    public void run() {
        //持有资源
        synchronized (waitObj) {
            System.out.println(Thread.currentThread().getName()+"占用资源");
            try {
                waitObj.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"释放资源");
        }
    }
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(new WaitDemo(),"对比线程");
        thread.start();
        Thread.sleep(3000L);
        synchronized (waitObj) {
            waitObj.notify();
        }
    }
}


在上诉代码的基础上增加了一个线程,会发生死锁现象


分析如下:


1、对比线程1会先获取到锁,然后进入wait状态(挂起在waitObj锁上),并释放锁资源

2、主线程继续执行,创建了对比线程2,对比线程2发现锁空闲,就可以持有锁进入syncronized方法体

3、对比线程2执行到wait语句,也挂起在waitObj锁上,并释放当前持有的锁

4.1、主线程继续执行到notify()方法,会随机唤醒挂起在waitObj上的一个线程,然后这个线程继续执行完毕以后释放锁,剩余的一个线程将继续挂起在waitObj上且没有其他线程唤醒,导致发生死锁

4.2、主线程继续执行到notifyAll()方法,会唤醒挂起在waitObj上的全部线程,然后所有线程执行完毕,不发生死锁

但后续主线程已经执行完毕了,也就是没有线程去主动唤醒对比线程2,导致线程2一直处于挂起状态,产生死锁!!!


public class WaitDemo implements Runnable {
    private static Object waitObj = new Object();
    @Override
    public void run() {
        //持有资源
        synchronized (waitObj) {
            System.out.println(Thread.currentThread().getName()+"占用资源");
            try {
                waitObj.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"释放资源");
        }
    }
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(new WaitDemo(),"对比线程1");
        thread.start();
        Thread thread2 = new Thread(new WaitDemo(),"对比线程2");
        thread2.start();
         Thread.sleep(3000L);
        synchronized (waitObj) {
            waitObj.notify();
            //waitObj.notifyAll();
        }
    }
}


vip算法班永久学习班: 800元/人

周一、周三、周五:8:30-9:30,周六、周日:10:30-11:30

报名方式:通过公众号导航栏的刷题群即可联系到我的微信号

vip永久班算法训练营

奔跑的小梁,公众号:梁霖编程工具库算法训练营快来参加吧~
相关文章
|
6月前
|
Java
使用notifyAll唤醒所有等待线程的方法与比较
使用notifyAll唤醒所有等待线程的方法与比较
|
6月前
|
Oracle Java 关系型数据库
面试知识点:notify是随机唤醒线程吗(唤醒线程顺序)?
面试知识点:notify是随机唤醒线程吗(唤醒线程顺序)?
217 0
|
7月前
|
监控 网络协议 iOS开发
程序退到后台的时候,所有线程被挂起,系统回收所有的socket资源问题及解决方案
程序退到后台的时候,所有线程被挂起,系统回收所有的socket资源问题及解决方案
259 0
|
安全 Java
AQS唤醒线程的时候为什么从后向前遍历
AQS唤醒线程的时候为什么从后向前遍历
1072 0
AQS唤醒线程的时候为什么从后向前遍历
|
Java
线程等待唤醒(等待通知)机制
线程等待唤醒(等待通知)机制
45 0
|
UED
QT多线程(主动挂起线程)
QT多线程(主动挂起线程)
186 0
线程发生阻塞,怎么唤醒线程?
线程发生阻塞,怎么唤醒线程?
255 0
|
安全 Java C++
JUC在深入面试题——三种方式实现线程等待和唤醒(wait/notify,await/signal,LockSupport的park/unpark)
JUC在深入面试题——三种方式实现线程等待和唤醒(wait/notify,await/signal,LockSupport的park/unpark)
227 1
JUC在深入面试题——三种方式实现线程等待和唤醒(wait/notify,await/signal,LockSupport的park/unpark)
|
安全 调度 开发者
并发异步编程之争:协程(asyncio)到底需不需要加锁?(线程/协程安全/挂起/主动切换)Python3
协程与线程向来焦孟不离,但事实上是,线程更被我们所熟知,在Python编程领域,单核同时间内只能有一个线程运行,这并不是什么缺陷,这实际上是符合客观逻辑的,单核处理器本来就没法同时处理两件事情,要同时进行多件事情本来就需要正在运行的让出处理器,然后才能去处理另一件事情,左手画方右手画圆在现实中本来就不成立,只不过这个让出的过程是线程调度器主动抢占的。
并发异步编程之争:协程(asyncio)到底需不需要加锁?(线程/协程安全/挂起/主动切换)Python3
|
调度
线程产生的虚假唤醒问题 原因和解决
多个线程并发争抢一个资源会产生线程虚假唤醒问题
135 0