【多线程】线程间通信三种方式代码实现

一、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("通知酱油到货了...");
		}
	}
}

输出结果:
酱油没了…

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值