LockSuport

java.util.concurrent.locks.LockSuport

  • 用于创建锁和其他同步类的基本线程阻塞原语。

    这个类与每个使用它的线程相关联,一个许可证(在Semaphore类的意义上)。 如果许可证可用,则呼叫parkpark返回,在此过程中消耗它; 否则可能会阻止。 致电unpark使许可证可用,如果尚不可用。 (与信号量不同,许可证不能累积,最多只有一个。)

    方法parkunpark提供了阻止和解除阻塞线程的有效手段,该方法不会遇到导致不推荐使用的方法Thread.suspendThread.resume目的不能使用的问题:一个线程调用park和另一个线程之间的尝试unpark线程将保持活跃性,由于许可证。 另外,如果调用者的线程被中断, park将返回,并且支持超时版本。 park方法也可以在任何其他时间返回,因为“无理由”,因此一般必须在返回之前重新检查条件的循环中被调用。 在这个意义上, park作为一个“忙碌等待”的优化,不浪费时间旋转,但必须与unpark配对才能有效。

    park的三种形式也支持blocker对象参数。 线程被阻止时记录此对象,以允许监视和诊断工具识别线程被阻止的原因。 (此类工具可以使用方法getBlocker(Thread)访问阻止程序 。)强烈鼓励使用这些形式而不是没有此参数的原始形式。 在锁实现中作为blocker提供的正常参数是this

    这些方法被设计为用作创建更高级同步实用程序的工具,并且本身对于大多数并发控制应用程序本身并不有用。 park方法仅用于形式的构造:

       while (!canProceed()) { ... LockSupport.park(this); } 
    其中既不canProceed也没有任何其他动作之前的呼叫park需要锁定或阻止。 因为只有一个许可证与每个线程相关联, park任何中介使用可能会干扰其预期效果。

 

 

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

  1、使用 Object 中的 wait() 方法让线程等待,使用Object中的 notify() 方法唤醒线程;

public class LockSupperDemo {
    public static Object object = new Object();

    public static void main(String[] args) {

        /**
         * 1、wait()和 notify()必须放在synchronized同步代码块中执行,
         * 否则会报错:java.lang.IllegalMonitorStateException
         *
         * 2、wait()和 notify()成对出现,并且必须先等待再唤醒,线程才能够被唤醒
         */
        new Thread(() -> {
            synchronized (object) {
                System.out.println(Thread.currentThread().getName() + "\t come in");
                try {
                    object.wait();//阻塞
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "\t 被唤醒");
            }
        }, "A").start();

        new Thread(() -> {
            synchronized (object) {
                object.notify();//唤醒
                System.out.println(Thread.currentThread().getName() + "\t 唤醒动作");
            }
        }, "B").start();

    }
}

 

  2、使用 JUC 中的 Condition 的 await() 方法让线程等待,使用 signal() 方法唤醒线程;

    public static Lock lock = new ReentrantLock();
    public static Condition condition = lock.newCondition();

    public static void main(String[] args){
        /**
         * 1、await()和 signal()必须放在 lock 代码块中执行,
         * 否则会报错:java.lang.IllegalMonitorStateException
         *
         * 2、await()和 signal()必须先等待再唤醒,线程才能够被唤醒
         */
        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();
            }
        },"A").start();

        new Thread(() -> {
            lock.lock();
            try {
                condition.signal();//唤醒
                System.out.println(Thread.currentThread().getName() + "\t 唤醒动作");
            }finally {
                lock.unlock();
            }
        }, "B").start();
    }

 

  3、使用 LockSupport 类可以阻塞当前线程以及唤醒指定被阻塞的线程;

static void park()
禁止当前线程进行线程调度,除非许可证可用。
static void park(Object blocker)
禁止当前线程进行线程调度,除非许可证可用。
static void
unpark(Thread thread)
为给定的线程提供许可证(如果尚未提供)。

 

LockSupport类使用了一种名为Permit(许可)的概念来做到阻塞和唤醒线程的功能,每个线程都有一个许可(permit);

permit只有两个值 0和1,默认为0;

    public static void main(String[] args){
        /**
         * 1、不需要放在锁代码块中
         *
         * 2、先唤醒后阻塞,线程照样执行
         */
        Thread a = new Thread(() ->{
            System.out.println(Thread.currentThread().getName() + "\t come in");
            LockSupport.park();//阻塞。。需要一个许可证
            System.out.println(Thread.currentThread().getName() + "\t 被唤醒");
        },"a");
        a.start();

        new Thread(() ->{
            LockSupport.unpark(a);//给a线程发放许可证
            System.out.println(Thread.currentThread().getName() + "\t 唤醒动作");
        },"B").start();

    }

 

 

posted @ 2021-04-15 14:34  DHaiLin  阅读(120)  评论(0编辑  收藏  举报