LockSupport
Posted greys
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LockSupport相关的知识,希望对你有一定的参考价值。
1、为什么想着了解LockSupport ?
因为 LockSupport 在底层的使用较多,它比内置锁( synchronized 隐式锁)使用起来更方便。通常使用的“等待——通知”有3种 (还可通过Atomic类实现):
(1) ReetrantLock 提供了一个 newCondition 方法 获取到 ConditionObject对象,通过condition, 我们可以调用 await() 和 signal 方法;
(2) 通过调用Object的 wait 和 notify 方法。 wait和notifyAll必须写在同步代码块中,而同步一般用 synchronized ,JDK1.8及更高的版本也推荐使用 synchronized ;
(3) 通过 LockSupport 调用 park 和 unpark 方法;
具体什么情况下使用什么方式,需我们充分了解 这3种方式的优缺点。
通过第2种方式实现:
public static void main(String[] args) throws InterruptedException { final Object obj = new Object(); Thread son = new Thread(new Runnable() { public void run() { try { synchronized (obj) { obj.wait(); } } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("son thread"); } }); son.start(); Thread.sleep(100); //阻塞wait方法 synchronized (obj) { obj.notifyAll(); } }
缺点:当我们注释掉sleep后,可能线程son一直处于运行中,因为son线程不是后台线程。
通过第3种方式实现:
public static void main(String[] args) throws InterruptedException { Thread son = new Thread(new Runnable() { @Override public void run() { LockSupport.park(); System.out.println("son thread"); } }); son.start(); Thread.sleep(100); LockSupport.unpark(son); }
通过测试,主线程不执行sleep,son线程也会正常执行退出。这就是LockSupport的灵活性。
2、jdk中哪些类使用了LockSupport
(1)我们在实现一个线程时,如果我们需要线程返回结果,那么我们要实现callable。我们通过Future取到返回值。
public static void main(String[] args) throws InterruptedException, ExecutionException { ArrayBlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(100); ThreadPoolExecutor pool = new ThreadPoolExecutor(4, 4, 100, TimeUnit.SECONDS, queue); Future<String> future = pool.submit(new Callable<String>() { @Override public String call() throws Exception { TimeUnit.MILLISECONDS.sleep(100); return UUID.randomUUID().toString(); } }); String result = future.get(); System.out.println(result); }
上面一段代码,当我们在使用future.get时,如果线程还没执行完,那么程序是不是有问题? 还是它会阻塞,等到线程执行完?
通过查看源码,可以找到结果。
继续深入awaitDone方法
可以看到awaitDone调用了LockSupport方法实现阻塞效果。那么线程怎么唤醒阻塞的线程了??? 当然是通过 run() 方法,猜想run执行完之后,通知等待线程。
查看set方法:
查看finishCompletion方法:
可以看到通知是用的unpark.
(2)上面main函数中使用了同步容器,其实jdk中容器都包含一个对象 Condition , Condition是个接口,它的实现类为ConditionObject。同步容器中维护了2个condition:notEmpty和notFull,调用await(),实际上就是ConditionObject的await()方法。
await()
另外:ConditionObject是 AbstractQueuedSynchronizer (AQS)的一个内部类。
3、LockSupport源码
lockSupport方法中调用的是 UNSAFE的native方法,需要openJDK查看。
park底层代码:
以上是关于LockSupport的主要内容,如果未能解决你的问题,请参考以下文章