#1、代码应用
public class FIFOMutex { //原子锁,类型为boolean private final AtomicBoolean locked = new AtomicBoolean(false); //等待队列 private final Queuewaiters = new ConcurrentLinkedQueue (); public void lock() { //获取当前线程,添加到等待队列中 boolean wasInterrupted = false; Thread current = Thread.currentThread(); waiters.add(current); // Block while not first in queue or cannot acquire lock //如果当前线程不是在等待队列头部或者无法获取锁信息 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); //为等待队列的第一个线程解除锁定。 //peek()获取头,但是不把头从队列里面删除 LockSupport.unpark(waiters.peek()); }}
#2、源码分析
##2.1、unsafe.objectFieldOffset
LockSupport代码有一段静态的代码段。
static { try { parkBlockerOffset = unsafe.objectFieldOffset (java.lang.Thread.class.getDeclaredField("parkBlocker")); } catch (Exception ex) { throw new Error(ex); }}
该代码段中unsafe.objectFieldOffset表示的含义是定位字段相对对象初始位置的偏移量。parkBlocker是Thead类的一个字段,该字段在LockSupport中的getBlocker()和setBlocker()方法中使用。具体的含义下文将有介绍。
##2.2、unsafe.putObject
LockSupport代码在设置对象某属性值的时候使用了内部的类方法。例如设置属性字段parkBlocker的值的时候,代码片段如下。
private static void setBlocker(Thread t, Object arg) { //设置线程对象t的字段parkBlocker,值为arg unsafe.putObject(t, parkBlockerOffset, arg); } ##2.3、Thread的parkBlocker
前面两小节都在说字段parkBlocker,可见其在LockSupport实现中的重要地位。那么它的具体作用是什么?
从javadoc上来看parkBlocker字段是工具,它能够记录线程阻塞信息以便监控和分析线程阻塞原因的。 ##2.4、方法介绍 如果线程不可访问则unpark方法使得指定线程可用访问,如果线程被阻塞,unpark方法将唤醒线程。否则下一次park方法调用保证不被阻塞。如果线程没有被开启,该方法不保证有任何影响。
public static void unpark(Thread thread) { if (thread != null) unsafe.unpark(thread);}
返回最后一次park方法调用,并且未调用unpark方法的线程返回的blocker。如果未被阻塞,则返回null。返回的值 只是内存快照。线程也许已经被其他的blocker 操作了unblocked或者blocked操作。
public static Object getBlocker(Thread t) { if (t == null) throw new NullPointerException(); return unsafe.getObjectVolatile(t, parkBlockerOffset);}
除非允许,否则失效所有现有线程的调度操作。 如果允许操作,那么马上处理并返回。否则现有线程将变成不可调度直到以下三种情况发生: 1、一切其他线程以该线程为目标调用了unpark方法。 2、其他线程打断了该线程。 3、伪造调用返回
public static void park() { unsafe.park(false, 0L);}