首页 > 其他分享 >LockSupport

LockSupport

时间:2024-10-28 20:45:50浏览次数:7  
标签:Thread park LockSupport 阻塞 线程 唤醒

LockSupport是什么

LockSupport是用来创建锁和其他同步类的基本线程阻塞原语,其中park()和unpack()而作用分别是阻塞线程解除阻塞线程.

线程等待唤醒机制

三种让线程等待和唤醒的方法

  • 方式一:使用Object中的wait()方法让线程等待,使用Object中的notify()方法唤醒线程
  • 方式二:使用JUC包中的Condition的await()方法让线程等待,使用signal()方法唤醒线程
  • 方式三:LockSupport类可以阻塞当前线程以及唤醒指定被阻塞的线程

Object类中的wait和notify方法实现线程等待和唤醒

局限性:

  1. wait和notify方法必须要在同步代码块或者同步方法里面,且成对出现使用
  2. 先wait再notify才ok
/**
 * Object类中的wait和notify方法实现线程等待和唤醒演示
 * @create 2023-04-11 12:13
 */
public class LockSupportDemo {

    public static void main(String[] args) {
        Object objectLock = new Object();
        /**
         * t1	 -----------come in
         * t2	 -----------发出通知
         * t1	 -------被唤醒
         */
        new Thread(() -> {
            synchronized (objectLock) {
                System.out.println(Thread.currentThread().getName() + "\t -----------come in");
                try {
                    objectLock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "\t -------被唤醒");
            }
        }, "t1").start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(() -> {
            synchronized (objectLock) {
                objectLock.notify();
                System.out.println(Thread.currentThread().getName() + "\t -----------发出通知");
            }

        }, "t2").start();
    }
}

Condition接口中的await和signal方法实现线程的等待和唤醒

局限性:

  1. Condition中的线程等待和唤醒方法,需要先获取锁
  2. 一定要先await后signal,不要反了
/**
 * Condition接口中的await和signal方法实现线程的等待和唤醒演示
 * @create 2023-04-11 12:13
 */
public class LockSupportDemo {

    public static void main(String[] args) {
        Lock lock = new ReentrantLock();
        Condition condition = lock.newCondition();
        /**
         * t1	 -----------come in
         * t2	 -----------发出通知
         * t1	 -----------被唤醒
         */
        new Thread(() -> {
            lock.lock();
            try {
                System.out.println(Thread.currentThread().getName() + "\t -----------come in");
                condition.await();
                System.out.println(Thread.currentThread().getName() + "\t -----------被唤醒");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }, "t1").start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(() -> {
            lock.lock();
            try {
                condition.signal();
                System.out.println(Thread.currentThread().getName() + "\t -----------发出通知");
            } finally {
                lock.unlock();
            }
        }, "t2").start();

    }
}

上述两个对象Object和Condition使用的限制条件

  1. 线程需要先获得并持有锁,必须在锁块(synchronized或lock)
  2. 必须要先等待后唤醒,线程才能够被唤醒

所以需要引入LockSupport

LockSupport类中的park等待和unpark唤醒

  • 是什么
    • LockSupport 是用于创建锁和其他同步类的基本线程阻塞原语
    • LockSupport类使用了一种名为Permit(许可)的概念来做到阻塞和唤醒线程的功能,每个线程都有一个许可(Permit),许可证只能有一个,累加上限是1
  • 主要方法
    • 阻塞: Peimit许可证默认没有不能放行,所以一开始调用park()方法当前线程会阻塞,直到别的线程给当前线程发放peimit,park方法才会被唤醒。
      • park/park(Object blocker)-------阻塞当前线程/阻塞传入的具体线程
    • 唤醒: 调用unpack(thread)方法后 就会将thread线程的许可证peimit发放,会自动唤醒park线程,即之前阻塞中的LockSupport.park()方法会立即返回。
      • unpark(Thread thread)------唤醒处于阻塞状态的指定线程
  • 代码
/**
 * LockSupport类中的park等待和unpark唤醒演示
 * @create 2023-04-11 12:13
 */
public class LockSupportDemo {

    public static void main(String[] args) {
        /**
         * t1	 -----------come in
         * t2	 ----------发出通知
         * t1	 ----------被唤醒
         */
        Thread t1 = new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + "\t -----------come in");
            LockSupport.park();
            System.out.println(Thread.currentThread().getName() + "\t ----------被唤醒");
        }, "t1");
        t1.start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(() -> {
            LockSupport.unpark(t1);
            System.out.println(Thread.currentThread().getName() + "\t ----------发出通知");
        }, "t2").start();

    }
}
  • 重点说明(重要)
    • LockSupport是用来创建锁和其他同步类的基本线程阻塞原语,所有的方法都是静态方法,可以让线程再任意位置阻塞,阻塞后也有对应的唤醒方法。归根结底,LockSupport时调用Unsafe中的native代码
    • LockSupport提供park()和unpark()方法实现阻塞线程和解除线程阻塞的过程,LockSupport和每个使用它的线程都有一个许可(Peimit)关联,每个线程都有一个相关的permit,peimit最多只有一个,重复调用unpark也不会积累凭证。
    • 形象理解:线程阻塞需要消耗凭证(Permit),这个凭证最多只有一个
      • 当调用park时,如果有凭证,则会直接消耗掉这个凭证然后正常退出。如果没有凭证,则必须阻塞等待凭证可用;
      • 当调用unpark时,它会增加一个凭证,但凭证最多只能有1个,累加无效。
  • 面试题
    • 为什么LockSupport可以突破wait/notify的原有调用顺序?
      • 因为unpark获得了一个凭证,之后再调用park方法,就可以名正言顺的凭证消费,故不会阻塞,先发放了凭证后续可以畅通无阻。
    • 为什么唤醒两次后阻塞两次,但最终结果还会阻塞线程?
      • 因为凭证的数量最多为1,连续调用两次unpark和调用一次unpark效果一样,只会增加一个凭证,而调用两次park却需要消费两个凭证,证不够,不能放行。

标签:Thread,park,LockSupport,阻塞,线程,唤醒
From: https://blog.csdn.net/jonas80029735/article/details/143313332

相关文章

  • LockSupport
    LockSupprot用来阻塞和唤醒线程,底层实现依赖于Unsafe类(后面会细讲)。该类包含一组用于阻塞和唤醒线程的静态方法,这些方法主要是围绕park和unpark展开。publicclassMain{publicstaticvoidmain(String[]args){ThreadmainThread=Thread.currentThre......
  • JUC工具(LockSupport)
    LockSupport用来创建锁和其他同步类的基本线程阻塞LockSupport用来创建锁和其他同步类的基本线程阻塞原语。简而言之,当调用LockSupport.park时,表示当前线程将会等待,直至获得许可,当调用LockSupport.unpark时,必须把等待获得许可的线程作为参数进行传递,好让此线程继续运行LockSuppo......
  • 【JDK】LockSupport 工具类
    1 前言LockSupport工具类最近复习到这个类了,之前也没做笔记,这里简单回顾下哈。JDK中的rt.jar包里面的LockSupport是个工具类,它的主要作用是挂起和唤醒线程,该工具类是创建锁和其他同步类的基础。LockSupport类与每个使用它的线程都会关联一个许可证,在默认情况下调用L......
  • 【Java 并发编程】LockSupport
    目录简介方法介绍阻塞和唤醒示例示例1示例2示例3阻塞对象blocker的作用和显式锁、隐式锁等待唤醒的区别简介java.util.concurrent.locks.LockSupport是一个工具类,提供了基本的线程阻塞和唤醒功能,它是创建锁和其他同步组件的基础工具,内部是基于sun.misc.Unsafe类实现的。Lo......
  • 20230608 java.util.concurrent.locks.LockSupport
    介绍java.util.concurrent.locks.LockSupportpublicclassLockSupportAPIstaticsetCurrentBlockervoidsetCurrentBlocker(Objectblocker)设置当前线程的阻塞对象getBlockerObjectgetBlocker(Threadt)返回提供给最近一次调用尚未解除阻塞的park方法的阻塞......
  • 一文读懂LockSupport
    阅读本文前,需要储备的知识点如下,点击链接直接跳转。java线程详解Java不能操作内存?Unsafe了解一下LockSupport介绍搞java开发的基本都知道J.U.C并发包(即java.util.concurrent包),所有并发相关的类基本都来自于这个包下,这个包是JDK1.5以后由祖师爷DougLea写的,LockSupport也是在这......
  • 忘记LockSupport怎么用了?那我们举个有趣的小例子,永远记住它!
    概述LockSupport是一个非常方便实用的线程阻塞工具,它可以在线程内任意位置让线程阻塞。和Thread.suspend()相比,它弥补了由于resume()在前发生,导致线程无法继续执行的情况。和Object.wait()方法相比,它不需要先获得某个对象的锁,也不会抛出InterruptedException异常。park()可以阻塞......
  • LockSupport与线程中断
    1LockSupport是什么LockSupport是用来创建锁和其他同步类的基本阻塞原语。park方法可以阻塞线程,unpark方法可以唤醒线程。与object的wait和notify不同的是,不需要synchonized的限制,没有先后顺序的限制。2线程中断线程不应该被其他线程中断,应该自己中断。线程的三个中断方法......
  • 四、JUC-LockSupport与线程中断
    一、线程中断机制1、概述一个线程不应该由其他线程来强制中断或停止,而是应该由线程自己自行停止,所以,Thread.stop、Thread.suspend、Thread.resume都已经被废弃了在Java中没有办法立即停止一条线程,然而停止线程却显得尤为重要,如取消一个耗时操作。因此,Java提供了一种用于......
  • JUC并发编程基础篇第六章之LockSupport[notify,signal之外的另一种唤醒方式]
    目录1、LockSupport有什么用2、使用wait和notify唤醒一个线程2.1、正常情况2.2、异常情况2,这里去掉了synchronized(o){}代码块2.3、异常情况3先notify再wait3、使用await和signal唤醒一个线程3.1、正常情况3.2、异常情况:如果去除锁块3.3、异常情况:先执行signal......