快速了解LockSupport

什么是LockSupport

官方一句话解释:

Basic thread blocking primitives for creating locks and other synchronization classes.
翻译:用于创建锁和其他同步类的基本线程阻塞原语。

常用的api:

public static void unpark(Thread thread)

根据传入的线程,解除该线程阻塞状态

public static void park()

阻塞当前调用该方法的线程,如main线程、new出来的线程在重写方法中调用

public static void park(Object blocker)

阻塞当前调用该方法的线程,在此基础上指定负责此线程的同步对象

public static void parkNanos(Object blocker, long nanos)

阻塞当前调用该方法的线程,如果超过nanos(纳秒)后自动释放

public static Object getBlocker(Thread t)

如果在调用用park方法时使用了传入Object的方法,在后续使用该方法可以获得这个同步对象

public static void parkUntil(long deadline)

阻塞当前调用该方法的线程,直到到了deadline(毫秒)时间,将自动释放

LockSupport基本使用方式

先park加锁,再unpark解锁

@Slf4j
public class LockSupportStudy {

    public static void main(String[] args) throws InterruptedException {
    
       Thread extThread = new Thread(() -> {
            LockSupport.park();
            log.info("enter extThread");
        });
        extThread.start();

        //确保其加上了锁。
        Thread.sleep(2000L);

        LockSupport.unpark(extThread);
    }
}

对extThread线程先加锁,main线程对其解锁成功
结果:
在这里插入图片描述
先unpark解锁,再park加锁(将其理解为凭证,不同线程之间,1个凭证消耗一次)

@Slf4j
public class LockSupportStudy {

    public static void main(String[] args) throws InterruptedException {

       Thread curThread = Thread.currentThread();
        Thread extThread = new Thread(() -> {
            LockSupport.unpark(curThread);
        });
        extThread.start();

        //确保其执行了unpark。
        Thread.sleep(2000L);

        LockSupport.park();
        log.info("main thread end");

    }
}

extThread线程先执行对于main线程的unpark,main线程中加锁并没有阻塞,说明先执行的unpark消耗了这个park的凭证
结果:
在这里插入图片描述

@Slf4j
public class LockSupportStudy {

    public static void main(String[] args) throws InterruptedException {

         //object作为锁
        Object lock = new Object();
        log.info("the blocker" + lock);

        Thread extThread = new Thread(() -> {
            LockSupport.park(lock);
        });
        extThread.start();

        //确保加完了锁
        Thread.sleep(2000L);

        log.info("the blocker:" + LockSupport.getBlocker(extThread));
        LockSupport.unpark(extThread);
        log.info("the blocker:" + LockSupport.getBlocker(extThread));

        log.info("main thread end");
    }
}

结果
在这里插入图片描述
使用public static void park(Object blocker) 方法,park方法后可以通过getBlocker方法,获得该锁的对象。
而可见在unpark方法后,该对象依然存在,所以将在下次使用时刷新。

@Slf4j
public class LockSupportStudy {

    public static void main(String[] args){

        //记录开始时间
        Long startTime = System.currentTimeMillis();

        long l = TimeUnit.SECONDS.toNanos(3);
        LockSupport.parkNanos(l);
        log.info(System.currentTimeMillis() - startTime + "");

        log.info("main thread end");

    }
}

结果
在这里插入图片描述
在3s时间过后,不再阻塞,哪怕没有调用unpark方法。

@Slf4j
public class LockSupportStudy {

    public static void main(String[] args) {

        //记录开始时间
        Long startTime = System.currentTimeMillis();

        LockSupport.parkUntil(System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(3));
        log.info(System.currentTimeMillis() - startTime + "");

        log.info("main thread end");

    }
}

设定其加锁,在加锁时间过3s后自动解锁。

坑点

注意:针对于同一线程(没有其他线程参与的情况下),若连续park两次,则无法正常解锁;针对于同一线程中连续unpark多次相当于只有一次。

@Slf4j
public class LockSupportStudy {

    public static void main(String[] args) throws InterruptedException {
        LockSupport.unpark(Thread.currentThread());
        LockSupport.unpark(Thread.currentThread());

        LockSupport.park();
        LockSupport.park();

        log.info("main thread end");

    }
}

结果
在这里插入图片描述
无法解锁

@Slf4j
public class LockSupportStudy {

    public static void main(String[] args) throws InterruptedException {

        Thread curThread = Thread.currentThread();

        Thread extThread = new Thread(() -> {
            LockSupport.unpark(curThread);
        });
        extThread.start();

        Thread extThread2 = new Thread(() -> {
            LockSupport.unpark(curThread);
        });
        extThread2.start();

        LockSupport.park();
        LockSupport.park();

        log.info("main thread end");

    }
}

结果:在这里插入图片描述
这种情况下是正巧在多线程的情况下达到了:
extThread执行针对main线程的unpark-》
main线程的park方法1执行=》(第一个凭证正常消耗)
extThread2执行针对main线程的unpark=》
main线程的park方法2执行(第二个凭证正常消耗)
的串型效果(每组park/unpark顺序可调换),所以能够解锁。

如果两个extThread 的unpark方法执行以后再运行第一句LockSupport.park(),那么就无法解锁。

结论

不要在同一个线程中连续调用两次unpark方法,再调用两次park方法,这是错误的用法,会造成当前线程永久阻塞,除非你park N 次,并且另起 N 个线程,每个线程去执行针对该线程的unpark方法。
一般的用法是对于某线程使用一组park/unpark方法,顺序看情况使用,该方法比一般的同步块中的wait/notify等方法更清晰简洁和灵活。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值