LockSupport使用,以及与wait/notify await/signal的比较

LockSupport通过pack 和 unpark 的方法来实现阻塞和唤醒线程的操作

Locksupport l类使用了一种名为permit 许可证的概念来做到阻塞和唤醒线程的功能,每个线程都有一个许可证permit,Permit只有两个值 1 和0 默认是0

使用Locksupport 的pack 和unpark方法 实现wait/notify   await/signal的阻塞 唤醒功能

1.使用wait/notify阻塞唤醒

package com.example.starter;

public class LockSupportDemo {
  static Object objectLock = new Object();
  public static void main(String[] args) {
    new Thread(()->{
      synchronized (objectLock){
        System.out.println(Thread.currentThread().getName()+"  come in ");
        try {
          objectLock.wait();
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+" 被唤醒");
      }

    },"AA").start();

    new Thread(()->{
      synchronized (objectLock){
        objectLock.notify();
        System.out.println(Thread.currentThread().getName()+"  通知");
      }
    },"BB").start();
  }
}

结果

AA  come in 
BB  通知
AA 被唤醒

不足:必须绑定synchronize使用,如果线程BB先运行,那么线程AA将永远不会被唤醒

 

2.使用await/signal的方式实现阻塞唤醒

public class LockSupportDemo {
  static Object objectLock = new Object();
  static Lock lock = new ReentrantLock();
  static Condition condition = lock.newCondition();
  public static void main(String[] args) {
    new Thread(() ->{
      /*try {
        TimeUnit.SECONDS.sleep(3);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }*/
      lock.lock();
      try {
        System.out.println(Thread.currentThread().getName()+"  come in ");
        condition.await();
      } catch (InterruptedException e) {
        e.printStackTrace();
      }finally {
        lock.unlock();
      }
      System.out.println(Thread.currentThread().getName()+" 被唤醒");

    },"AA").start();

    new Thread(()->{
      lock.lock();
      try {
        condition.signal();
      } catch (Exception e) {
        e.printStackTrace();
      }finally {
        lock.unlock();
      }
      System.out.println(Thread.currentThread().getName()+"  通知");
    },"BB").start();

  }

结果

 

AA  come in 
BB  通知
AA 被唤醒

不足:必须绑定Lock使用,如果线程BB先运行,那么线程AA将永远不会被唤醒

3.使用lockSupport 的park 和unpark的方式

public class LockSupportDemo {

  static Object objectLock = new Object();

  static Lock lock = new ReentrantLock();

  static Condition condition = lock.newCondition();



  public static void main(String[] args) {

    Thread threadA = new Thread(() -> {

      try {

        TimeUnit.SECONDS.sleep(3);

      } catch (InterruptedException e) {

        e.printStackTrace();

      }

      System.out.println(Thread.currentThread().getName()+"  come in ");

      LockSupport.park();

      System.out.println(Thread.currentThread().getName()+" 被唤醒");

      }, "AA");

    threadA.start();





    new Thread(() -> {

      LockSupport.unpark(threadA);

      System.out.println(Thread.currentThread().getName()+" 通知了");

    }, "BB").start();

  }

 结果

AA  come in 
BB  通知
AA 被唤醒

优点:不在依赖任何其他组件,BB线程先运行 AA也能正常唤醒

注意调用两次unpark  和 park  无论调用多少次unpark都只会发放一次通行证,而调用几次park就会要几张通行证,如下代码所示,会导致AA无法唤醒

 

public class LockSupportDemo {
  static Object objectLock = new Object();
  static Lock lock = new ReentrantLock();
  static Condition condition = lock.newCondition();

  public static void main(String[] args) {
    Thread threadA = new Thread(() -> {

      System.out.println(Thread.currentThread().getName()+"  come in ");
      LockSupport.park();
      LockSupport.park();
      System.out.println(Thread.currentThread().getName()+" 被唤醒");
      }, "AA");
    threadA.start();

    try {
      TimeUnit.SECONDS.sleep(3);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    new Thread(() -> {
      LockSupport.unpark(threadA);
      LockSupport.unpark(threadA);
      System.out.println(Thread.currentThread().getName()+" 通知了");
    }, "BB").start();
  }

结果

AA  come in 
BB 通知了

关注下park和unpark的底层实现:

都是调用的底层unsafe类

LockSupport使用,以及与wait/notify await/signal的比较LockSupport使用,以及与wait/notify await/signal的比较

 

上一篇:进程间通信


下一篇:js 中filter 什么时候加return