java线程通讯的方式

java线程通讯的方式主要有三种

  1. suspend/resume
  2. wait/notify
  3. park/unpark

suspend/resume

  1. 正常的suspend/resume
public void suspendResumeTest() throws Exception {
    
    
   // public static Object baozidian = null;
   // 启动线程
   Thread consumerThread = new Thread(() -> {
    
    
   	if (baozidian == null) {
    
     // 如果没包子,则进入等待
   		System.out.println("1、进入等待");
   		Thread.currentThread().suspend();
   	}
   	System.out.println("2、买到包子,回家");
   });
   consumerThread.start();
   // 3秒之后,生产一个包子
   Thread.sleep(3000L);
   baozidian = new Object();
   consumerThread.resume();
   System.out.println("3、通知消费者");
   }
  1. 死锁的suspend/resume: suspend并不会像wait一样释放锁,故此容易写出死锁代码
public void suspendResumeDeadLockTest() throws Exception {
    
    
	// public static Object baozidian = null;
	// 启动线程
	Thread consumerThread = new Thread(() -> {
    
    
		if (baozidian == null) {
    
     // 如果没包子,则进入等待
			System.out.println("1、进入等待");
			// 当前线程拿到锁,然后挂起
			synchronized (this) {
    
    
				Thread.currentThread().suspend();
			}
		}
		System.out.println("2、买到包子,回家");
	});
	consumerThread.start();
	// 3秒之后,生产一个包子
	Thread.sleep(3000L);
	baozidian = new Object();
	// 争取到锁以后,再恢复consumerThread
	synchronized (this) {
    
    
		consumerThread.resume();
	}
	System.out.println("3、通知消费者");
}
  1. 导致程序永久挂起的suspend/resume
public void suspendResumeDeadLockTest2() throws Exception {
    
    
	// public static Object baozidian = null;
	// 启动线程
	Thread consumerThread = new Thread(() -> {
    
    
		if (baozidian == null) {
    
    
			System.out.println("1、没包子,进入等待");
			try {
    
     // 为这个线程加上一点延时
				Thread.sleep(5000L);
			} catch (InterruptedException e) {
    
    
				e.printStackTrace();
			}
			// 这里的挂起执行在resume后面
			Thread.currentThread().suspend();
		}
		System.out.println("2、买到包子,回家");
	});
	consumerThread.start();
	// 3秒之后,生产一个包子
	Thread.sleep(3000L);
	baozidian = new Object();
	consumerThread.resume();
	System.out.println("3、通知消费者");
	consumerThread.join();
}

wait/notify

  1. 正常的wait/notify
public void waitNotifyTest() throws Exception {
    
    
	// public static Object baozidian = null;
	// 启动线程
	new Thread(() -> {
    
    
		if (baozidian == null) {
    
     // 如果没包子,则进入等待
			synchronized (this) {
    
    
				try {
    
    
					System.out.println("1、进入等待");
					this.wait();
				} catch (InterruptedException e) {
    
    
					e.printStackTrace();
				}
			}
		}
		System.out.println("2、买到包子,回家");
	}).start();
	// 3秒之后,生产一个包子
	Thread.sleep(3000L);
	baozidian = new Object();
	synchronized (this) {
    
    
		this.notifyAll();
		System.out.println("3、通知消费者");
	}
}
  1. 会导致程序永久等待的wait/notify
public void waitNotifyDeadLockTest() throws Exception {
    
    
	// public static Object baozidian = null;
	// 启动线程
	new Thread(() -> {
    
    
		if (baozidian == null) {
    
     // 如果没包子,则进入等待
			try {
    
    
				Thread.sleep(5000L);
			} catch (InterruptedException e1) {
    
    
				e1.printStackTrace();
			}
			synchronized (this) {
    
    
				try {
    
    
					System.out.println("1、进入等待");
					this.wait();
				} catch (InterruptedException e) {
    
    
					e.printStackTrace();
				}
			}
		}
		System.out.println("2、买到包子,回家");
	}).start();
	// 3秒之后,生产一个包子
	Thread.sleep(3000L);
	baozidian = new Object();
	synchronized (this) {
    
    
		this.notifyAll();
		System.out.println("3、通知消费者");
	}
}

park/unpark

  1. 正常的park/unpark
public void parkUnParkTest() throws Exception {
    
    
    // public static Object baozidian = null;
	// 启动线程
	Thread consumerThread = new Thread(() -> {
    
    
		if (baozidian == null) {
    
     // 如果没包子,则进入等待
			System.out.println("1、进入等待");
			LockSupport.park();
		}
		System.out.println("2、买到包子,回家");
	});
	consumerThread.start();
	// 3秒之后,生产一个包子
	Thread.sleep(3000L);
	baozidian = new Object();
	LockSupport.unpark(consumerThread);
	System.out.println("3、通知消费者");
}
  1. 死锁的park/unpark
public void parkUnParkDeadLockTest() throws Exception {
    
    
	// public static Object baozidian = null;
	// 启动线程
	Thread consumerThread = new Thread(() -> {
    
    
		if (baozidian == null) {
    
     // 如果没包子,则进入等待
			System.out.println("1、进入等待");
			// 当前线程拿到锁,然后挂起
			synchronized (this) {
    
    
				LockSupport.park();
			}
		}
		System.out.println("2、买到包子,回家");
	});
	consumerThread.start();
	// 3秒之后,生产一个包子
	Thread.sleep(3000L);
	baozidian = new Object();
	// 争取到锁以后,再恢复consumerThread
	synchronized (this) {
    
    
		LockSupport.unpark(consumerThread);
	}
	System.out.println("3、通知消费者");
}

总结

  1. suspend/resume对调用顺序有要求,也要开发自己注意锁的释放。这个被弃用的API, 容易死锁,也容易导致永久挂起。
  2. wait/notify要求再同步关键字里面使用,免去了死锁的困扰,但是一定要先调用wait,再调用notify,否则永久等待了
  3. park/unpark没有顺序要求,但是park并不会释放锁,所以在同步代码中使用要特别注意,防止出现死锁

猜你喜欢

转载自blog.csdn.net/a1774381324/article/details/120612121