java线程通讯的方式

简介: java线程通讯的方式

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



  1. suspend/resume


  1. wait/notify


  1. 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并不会释放锁,所以在同步代码中使用要特别注意,防止出现死锁


目录
相关文章
|
1天前
|
Java
【Java多线程】面试常考 —— JUC(java.util.concurrent) 的常见类
【Java多线程】面试常考 —— JUC(java.util.concurrent) 的常见类
9 0
|
1天前
|
设计模式 消息中间件 安全
【Java多线程】关于多线程的一些案例 —— 单例模式中的饿汉模式和懒汉模式以及阻塞队列
【Java多线程】关于多线程的一些案例 —— 单例模式中的饿汉模式和懒汉模式以及阻塞队列
8 0
|
1天前
|
安全 Java 程序员
【Java多线程】面试常考——锁策略、synchronized的锁升级优化过程以及CAS(Compare and swap)
【Java多线程】面试常考——锁策略、synchronized的锁升级优化过程以及CAS(Compare and swap)
5 0
|
1天前
|
Java 数据库
【Java多线程】对线程池的理解并模拟实现线程池
【Java多线程】对线程池的理解并模拟实现线程池
9 1
|
1天前
|
Java
【Java多线程】分析线程加锁导致的死锁问题以及解决方案
【Java多线程】分析线程加锁导致的死锁问题以及解决方案
9 1
|
1天前
|
存储 缓存 安全
【Java多线程】线程安全问题与解决方案
【Java多线程】线程安全问题与解决方案
8 1
|
1天前
|
Java 调度
【Java多线程】线程中几个常见的属性以及状态
【Java多线程】线程中几个常见的属性以及状态
7 0
|
1天前
|
Java API 调度
【Java多线程】Thread类的基本用法
【Java多线程】Thread类的基本用法
5 0
|
1天前
|
Java 调度
【Java多线程】对进程与线程的理解
【Java多线程】对进程与线程的理解
9 1
|
2天前
|
安全 Java 调度
Java多线程编程实践指南
Java多线程编程实践指南
11 0