绪
今天和朋友讨论Java中的锁机制的时候,谈论到了LockSupport类,在之前一直没有使用过该类,所以当提到该类的时候还是有点陌生,然后看了一下JDK的源码和该类相关的技术博客,整理了一下该类的原理和使用场景。
使用
package mthread;
import org.junit.Test;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;
/**
* 锁测试
* Start at: 2018/3/25 22:29
*
* @author muhong
*/
public class LockSupportTest {
/** 等待满足的条件 */
private volatile boolean finish = false;
@Test
public void test(){
Thread waiter = new Thread(()->{
long currentSeconds = TimeUnit.SECONDS.convert(System.currentTimeMillis(), TimeUnit.MILLISECONDS);
System.out.println(currentSeconds+":线程执行开始....并等待结束通知");
while (!finish){ // 由于park方法会被中断返回,所以需要重复检查“条件”
LockSupport.park(this);
}
currentSeconds = TimeUnit.SECONDS.convert(System.currentTimeMillis(), TimeUnit.MILLISECONDS);
System.out.println(currentSeconds+":线程执行结束");
});
waiter.start();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
long currentSeconds = TimeUnit.SECONDS.convert(System.currentTimeMillis(), TimeUnit.MILLISECONDS);
System.out.println(currentSeconds+":通知线程结束等待");
finish = true;
LockSupport.unpark(waiter);
}
}
源码解析
1、首先看看java doc描述
/**
* Basic thread blocking primitives for creating locks and other
* synchronization classes.
* 提供了创建锁信息的原生方法
*
* <p>This class associates, with each thread that uses it, a permit
* (in the sense of the {@link java.util.concurrent.Semaphore
* Semaphore} class). A call to {@code park} will return immediately
* if the permit is available, consuming it in the process; otherwise
* it <em>may</em> block. A call to {@code unpark} makes the permit
* available, if it was not already available. (Unlike with Semaphores
* though, permits do not accumulate. There is at most one.)
* 每一个线程都用于可以使用该类,当线程使用该类的时候,会生成一个permit(类似一个和信
* 号量相关作用的数据结构)和该线程关联,通过该permit完成锁相关的工作,该permit有一些
* 有别于锁的特性,具体特性如下。
*
* <p>Methods {@code park} and {@code unpark} provide efficient
* means of blocking and unblocking threads that do not encounter the
* problems that cause the deprecated methods {@code Thread.suspend}
* and {@code Thread.resume} to be unusable for such purposes: Races
* between one thread invoking {@code park} and another thread trying
* to {@code unpark} it will preserve liveness, due to the
* permit. Additionally, {@code park} will return if the caller's
* thread was interrupted, and timeout versions are supported. The
* {@code park} method may also return at any other time, for "no
* reason", so in general must be invoked within a loop that rechecks
* conditions upon return. In this sense {@code park} serves as an
* optimization of a "busy wait" that does not waste as much time
* spinning, but must be paired with an {@code unpark} to be
* effective.
* 该permit的特性是不会产生线程suspend和resume两种状态,即使在一个线程调用park
* 另外一个线程调用unpark的时候也会保持线程的活性。而且如果调用park方法的线程在阻塞
* 过程中被中断,那么park方法将立刻无条件返回,所以总得来说,在调用park方法的时候需要
* 循环检测通过LockSupport方法共享的资源是否满足条件,如果不满足条件那么需要继续park
* 一直等待到共享资源满足为止。从某种意义上来说,park方法其实是自旋锁的一种优化,避免了
* 忙等引起的CPU时间的浪费
*
* <p>The three forms of {@code park} each also support a
* {@code blocker} object parameter. This object is recorded while
* the thread is blocked to permit monitoring and diagnostic tools to
* identify the reasons that threads are blocked. (Such tools may
* access blockers using method {@link #getBlocker(Thread)}.)
* The use of these forms rather than the original forms without this
* parameter is strongly encouraged. The normal argument to supply as
* a {@code blocker} within a lock implementation is {@code this}.
* blocker用于记录当前线程在哪个对象上阻塞了,这样的记录可以方便的进行线程阻塞原因的
* 诊断和分析。
*
* <p>These methods are designed to be used as tools for creating
* higher-level synchronization utilities, and are not in themselves
* useful for most concurrency control applications. The {@code park}
* method is designed for use only in constructions of the form:
* 该类也可以用于实现更加上层的锁工具,而且她自身也是一个非常有用的并发控制程序。
*
* 下面是推荐是用方式:
*
* <pre> {@code
* while (!canProceed()) { ... LockSupport.park(this); }}</pre>
*
* where neither {@code canProceed} nor any other actions prior to the
* call to {@code park} entail locking or blocking. Because only one
* permit is associated with each thread, any intermediary uses of
* {@code park} could interfere with its intended effects.
*
* <p><b>Sample Usage.</b> Here is a sketch of a first-in-first-out
* non-reentrant lock class:
* <pre> {@code
* class FIFOMutex {
* private final AtomicBoolean locked = new AtomicBoolean(false);
* private final Queue<Thread> waiters
* = new ConcurrentLinkedQueue<Thread>();
*
* public void lock() {
* boolean wasInterrupted = false;
* Thread current = Thread.currentThread();
* waiters.add(current);
*
* // Block while not first in queue or cannot acquire lock
* // 循环检查共享资源条件是否满足(因为park返回并不代表共享资源满足条件)
* while (waiters.peek() != current ||
* !locked.compareAndSet(false, true)) {
* LockSupport.park(this);
* if (Thread.interrupted()) // ignore interrupts while waiting
* wasInterrupted = true;
* }
*
* waiters.remove();
* if (wasInterrupted) // reassert interrupt status on exit
* current.interrupt();
* }
*
* public void unlock() {
* locked.set(false);
* LockSupport.unpark(waiters.peek());
* }
* }}</pre>
*/
2、源码解读
在上面的java doc中已经对整个机制进行了详细的分析,而且该类的大部分功能逻辑依赖于jvm中的unsafe函数,所以就不再进行具体的分析了。