线程间通信三种方式代码实现
一、jdk弃用suspend/resume方式
当前线程调用suspend方法会被挂起,当再次调用resume时恢复执行。但suspend操作不会释放锁,容易造成死锁,且suspend必须在resume方法之前执行,编写程序易出死锁BUG,因此被jdk弃用。以生产者-消费者模型,我们分别演示下正常使用与死锁情况:
1、正常情况
public class ThreadCmuTest {
private static Object soySauce = null;
private volatile static Object BLOCK = new Object();
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
while (soySauce == null) {
System.out.println("酱油没了...");
Thread.currentThread().suspend();// 进入等待状态
}
System.out.println("打到酱油回家了...");
});
thread.start();
Thread.sleep(2000);
soySauce = new Object();
thread.resume();//恢复thread可执行
System.out.println("通知酱油到货了...");
}
}
输出结果:
酱油没了…
通知酱油到货了…
打到酱油回家了…
2、同步块中请求同一把锁造成死锁
public class ThreadCmuTest {
private static Object soySauce = null;
private volatile static Object BLOCK = new Object();
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
while (soySauce == null) {
synchronized (BLOCK) {
System.out.println("酱油没了...");
Thread.currentThread().suspend();// 进入等待状态,不会释放BLOCK锁
}
}
System.out.println("打到酱油回家了...");
});
thread.start();
Thread.sleep(2000);
synchronized (BLOCK) {//主线程这里拿不到BLOCK锁对象,造成死锁
soySauce = new Object();
thread.resume();
System.out.println("通知酱油到货了...");
}
}
}
输出结果:
酱油没了…
3、执行顺序造成死锁
public class ThreadCmuTest {
private static Object soySauce = null;
private volatile static Object BLOCK = new Object();
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
while (soySauce == null) {
System.out.println("酱油没了...");
try {
Thread.sleep(5000);//5秒之后再挂起
} catch (InterruptedException e) {
e.printStackTrace();
}
Thread.currentThread().suspend();// 进入等待状态
}
System.out.println("打到酱油回家了...");
});
thread.start();
Thread.sleep(2000);
soySauce = new Object();
thread.resume();//这里resume先执行
System.out.println("通知酱油到货了...");
}
}
输出结果:
酱油没了…
通知酱油到货了…
二、wait/notify通信
wait/notify方法必须由持有同一对象锁的线程调用,及同步代码块中,wait方法使当前线程进入等待状态,并且释放当前锁,等待其他线程调用notify/notifyAll唤醒。但wait/notify方法也与执行顺序有关,不然也会造成死锁状态。
1、正常情况
public class ThreadCmuTest {
private static Object soySauce = null;
private volatile static Object BLOCK = new Object();
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
while (soySauce == null) {
synchronized (BLOCK) {
System.out.println("酱油没了...");
try {
BLOCK.wait();//当前线程进入等待状态并释放BLOCK锁
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
System.out.println("打到酱油回家了...");
});
thread.start();
Thread.sleep(3000);
soySauce = new Object();
synchronized (BLOCK) {
BLOCK.notifyAll();//必须由同一持有BLOCK线程锁对象调用
System.out.println("通知酱油到货了...");
}
}
}
输出结果:
酱油没了…
通知酱油到货了…
打到酱油回家了…
2、执行顺序造成死锁
public class ThreadCmuTest {
private static Object soySauce = null;
private volatile static Object BLOCK = new Object();
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
while (soySauce == null) {
try {
Thread.sleep(5000);//等待5秒再去获取锁进入等待状态
} catch (InterruptedException e1) {
e1.printStackTrace();
}
synchronized (BLOCK) {
System.out.println("酱油没了...");
try {
BLOCK.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
System.out.println("打到酱油回家了...");
});
thread.start();
Thread.sleep(2000);
soySauce = new Object();
synchronized (BLOCK) {
BLOCK.notifyAll();//此处会比wait先执行
System.out.println("通知酱油到货了...");
}
}
输出结果:
通知酱油到货了…
酱油没了…
三、park/unpark通信
park/unpark需要使用LockSupport工具调用,当线程中调用park方法会进入等待状态,等待许可颁发,unpark方法会给指定线程颁发许可,恢复其可运行状态。park/unpark方法不要求执行顺序,先unpark颁发许可,再调park时已存在许可,会直接执行。但park/unpark不会释放锁,也会造成死锁情况。
1、正常情况
public class ThreadCmuTest {
private static Object soySauce = null;
private volatile static Object BLOCK = new Object();
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
while (soySauce == null) {
System.out.println("酱油没了...");
LockSupport.park();//当前线程进入等待许可状态
}
System.out.println("打到酱油回家了...");
});
thread.start();
Thread.sleep(3000);
soySauce = new Object();
LockSupport.unpark(thread);//给thread线程许可,恢复其可运行状态
System.out.println("通知酱油到货了...");
}
}
输出结果:
酱油没了…
通知酱油到货了…
打到酱油回家了…
2、同步代码块请求同一把锁造成死锁
public class ThreadCmuTest {
private static Object soySauce = null;
private volatile static Object BLOCK = new Object();
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
while (soySauce == null) {
synchronized (BLOCK) {
System.out.println("酱油没了...");
LockSupport.park();//当前线程进入等待许可状态,但不会释放BLOCK锁
}
}
System.out.println("打到酱油回家了...");
});
thread.start();
Thread.sleep(3000);
soySauce = new Object();
synchronized (BLOCK) {//此时拿不到BLOCK锁,造成死锁
LockSupport.unpark(thread);//给thread线程颁发许可
System.out.println("通知酱油到货了...");
}
}
}
输出结果:
酱油没了…