什么是线程间通信?
线程的挂起操作实质上就是使线程进入“非执行”状态下,在这个状态下CPU不会分给线程时间片,进入这个状态可以用来暂停一个线程的运行。在线程挂起后,可以通过重新唤醒线程来使其恢复运行
为什么要挂起线程?
cpu分配的时间片非常短、同时也非常严重。避免资源的浪费。
如何挂起线程?
被废弃的方法
thread.suspend()
该方法不会释放线程所占用的资源。如果使用该方法将某个线程挂起,则可能会使其他等待资源的线程死锁thread.resume()
方法本身并无问题,但不能独立于 suspend() 方法存在- 例子
- 基础的暂停的演示
package com.xdclass.thread.hang; /** * 挂起操作的Demo */ public class SuspendDemo implements Runnable { @Override public void run() { System.out.println(Thread.currentThread().getName()+"执行run方法,准备调用suspend方法"); //挂起线程 Thread.currentThread().suspend(); System.out.println(Thread.currentThread().getName()+"执行run方法,调用suspend方法结束"); } public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(new SuspendDemo()); thread.start(); Thread.sleep(3000L); //对线程进行唤醒操作 thread.resume(); } }
- 制作死锁的演示
package com.xdclass.thread.hang; /** * suspend 死锁演示 */ public class DeadDemo implements Runnable{ private static Object object = new Object(); @Override public void run() { //持有资源 synchronized (object) { System.out.println(Thread.currentThread().getName()+"占用资源"); Thread.currentThread().suspend(); } System.out.println(Thread.currentThread().getName()+"释放资源"); } public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(new DeadDemo(),"对比线程"); thread.start(); Thread.sleep(1000L); thread.resume(); Thread deadThread = new Thread(new DeadDemo(),"死锁线程"); deadThread.start(); deadThread.resume(); } }
- 基础的暂停的演示
用法
-
wait()
暂停执行、放弃已经获得的锁、进入等待状态 -
notify()
随机唤醒一个处于等待锁的线程 -
notifyAll()
唤醒所有处于等待锁的线程,自行抢占cpu资源 -
例子
package com.xdclass.thread.hang; 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 thread2 = new Thread(new WaitDemo(),"对比线程2"); thread2.start(); Thread.sleep(3000L); synchronized (waitObj) { // 改成notifyAll()可一次唤醒所有wait状态的线程,notify()只能唤醒一次,而且是按照进入synchronized的顺序来地 waitObj.notify(); waitObj.notify(); } } }
结果是:
对比线程占用资源 对比线程2占用资源 对比线程2释放资源 对比线程释放资源
可以看到notify每次只通知一个线程,如果想唤醒所有的,把两个notify()改成notifyAll()即可
什么时候适合使用挂起线程?
我等的船还没来(等待未确定的资源),我等的人还没来。直到通知方法被调用