标签:sum bsp logs creating erro argument ref 用法 简单
Basic thread blocking primitives for creating locks and other synchronization classes.用来创建锁及其他同步类的基础线程阻塞原语。这是java doc中的解释,以下是一个先进先出 (first-in-first-out) 非重入锁类的框架。
* 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 * 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()); * }
上述代码简单实现的锁功能,主要使用了LockSupport的park和unpark阻塞和释放线程,AtomicBoolean的CAS操作来判断是否持有锁ConcurrentLinkedQueue来保存等待线程,此队列是一个线程安全的队列,当前仅当线程在等待队列队首且持有锁才会跳出while循环,从等待队列中移除。
locked.compareAndSet(false, true)的语意为,期望AtomicBoolean对象的值为false,并设置值为true,可以做为是否持有锁的判断
方法摘要 | |
---|---|
static Object |
getBlocker(Thread t) 返回提供给最近一次尚未解除阻塞的 park 方法调用的 blocker 对象,如果该调用不受阻塞,则返回 null。 |
static void |
park() 为了线程调度,禁用当前线程,除非许可可用。 |
static void |
park(Object blocker) 为了线程调度,在许可可用之前禁用当前线程。 |
static void |
parkNanos(long nanos) 为了线程调度禁用当前线程,最多等待指定的等待时间,除非许可可用。 |
static void |
parkNanos(Object blocker, long nanos) 为了线程调度,在许可可用前禁用当前线程,并最多等待指定的等待时间。 |
static void |
parkUntil(long deadline) 为了线程调度,在指定的时限前禁用当前线程,除非许可可用。 |
static void |
parkUntil(Object blocker, long deadline) 为了线程调度,在指定的时限前禁用当前线程,除非许可可用。 |
static void |
unpark(Thread thread) 如果给定线程的许可尚不可用,则使其可用。 |
LockSupport提供的全部为static修饰的静态方法,作为一个工具类在使用。主要提供了阻塞线程,和解除阻塞线程的方法。
// Hotspot implementation via intrinsics API private static final Unsafe unsafe = Unsafe.getUnsafe(); //持有一个Unsafe的实例 private static final long parkBlockerOffset; //偏移量 static { try { parkBlockerOffset = unsafe.objectFieldOffset //初始化获取属性偏移量 (java.lang.Thread.class.getDeclaredField("parkBlocker")); } catch (Exception ex) { throw new Error(ex); } }
上一章中我们探讨过unsafe 的CAS用法,这里同样,LockSupport采用Unsafe类来获取属性修改属性,而且parkBlocker是Thread类的成员变量
/** * The argument supplied to the current call to * java.util.concurrent.locks.LockSupport.park. * Set by (private) java.util.concurrent.locks.LockSupport.setBlocker * Accessed using java.util.concurrent.locks.LockSupport.getBlocker */ volatile Object parkBlocker;
同样是volatile修饰,意为阻塞者,阻塞当前线程的 对象,这个属性为我们提供了可以监控线程被阻塞的信息方法。
private static void setBlocker(Thread t, Object arg) { // Even though volatile, hotspot doesn‘t need a write barrier here. unsafe.putObject(t, parkBlockerOffset, arg); } /** * Returns the blocker object supplied to the most recent * invocation of a park method that has not yet unblocked, or null * if not blocked. The value returned is just a momentary * snapshot -- the thread may have since unblocked or blocked on a * different blocker object. * * @param t the thread * @return the blocker * @throws NullPointerException if argument is null * @since 1.6 */ public static Object getBlocker(Thread t) { if (t == null) throw new NullPointerException(); return unsafe.getObjectVolatile(t, parkBlockerOffset);//根据属性偏移量获取属性值 }
为什么通过unsafe来获取线程的parkBlocker变量,而不是通过set和get方法获取?这是因为parkBlocker只有在线程被阻塞时才有意义,而此时set和get方法是无法通过线程对象调用的。
public native Object getObjectVolatile(Object var1, long var2); public native void putObjectVolatile(Object var1, long var2, Object var4);//var2 为属性在var1中的偏移量,var4为要设置的属性值
这是Unsafe类提供的native方法,具体实现在这里不再深究。
上面探索了LockSupport中对阻塞者信息的处理,下面来看下阻塞及解除阻塞函数。
public static void park(Object blocker) { Thread t = Thread.currentThread(); //当前线程 setBlocker(t, blocker); //设置被谁阻塞 unsafe.park(false, 0L); //阻塞线程 setBlocker(t, null); //线程解除阻塞,清空blocker信息 } public static void unpark(Thread thread) { if (thread != null) unsafe.unpark(thread); //解除线程阻塞 }
这是Unsafe类中实质阻塞线程及解除线程阻塞的native函数,var1指明时间为绝对时间还是相对时间,false为相对时间,var2意为解除阻塞时间,设置为0则只有当线程中断,或调用unpark函数时解除锁定,若不为0,则等待var2时间后也会自动解除阻塞,注意这里的时间单位为纳秒;当var1位true时,为绝对时间,var2的时间单位为毫秒
public native void unpark(Object var1); public native void park(boolean var1, long var2);
最多等待nanos纳秒
public static void parkNanos(Object blocker, long nanos) { if (nanos > 0) { Thread t = Thread.currentThread(); setBlocker(t, blocker); unsafe.park(false, nanos); setBlocker(t, null); } }
标签:sum bsp logs creating erro argument ref 用法 简单
原文地址:http://www.cnblogs.com/lscz3633/p/7605427.html