首页 > 编程语言 > 详细

LockSupport详解 | Java并发编程

时间:2015-09-01 02:10:02      阅读:308      评论:0      收藏:0      [点我收藏+]

??? 我们一再提线程、锁等概念,但锁是如果实现的呢?又是如何知道当前阻塞线程的又是哪个对象呢?

java.util.concurrent.locks.LockSupport这个类先说起,因为这个类实现了底层的一些方法,各种的锁实现都是这个基础上发展而来的。这个类方法很少,但理解起来需要花费一点时间,因为涉及了很多底层的知识,这些都是我们平时不关心的。

?

一:查看JDK源码

???
package java.util.concurrent.locks;
import java.util.concurrent.*;
import sun.misc.Unsafe;

/**
 * Basic thread blocking primitives for creating locks and other
 * synchronization classes.
 */
public class LockSupport {
    private LockSupport() {} // Cannot be instantiated.

    // Hotspot implementation via intrinsics API
    private static final Unsafe unsafe = Unsafe.getUnsafe();
    private static final long parkBlockerOffset;

    static {
        try {
            parkBlockerOffset = unsafe.objectFieldOffset
                (java.lang.Thread.class.getDeclaredField("parkBlocker"));
        } catch (Exception ex) { throw new Error(ex); }
    }

    private static void setBlocker(Thread t, Object arg) {
        // Even though volatile, hotspot doesn‘t need a write barrier here.
        unsafe.putObject(t, parkBlockerOffset, arg);
    }
    public static void unpark(Thread thread) {
        if (thread != null)
            unsafe.unpark(thread);
    }
    public static void park(Object blocker) {
        Thread t = Thread.currentThread();
        setBlocker(t, blocker);
        unsafe.park(false, 0L);
        setBlocker(t, null);
    }
    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);
        }
    }
    public static void parkUntil(Object blocker, long deadline) {
        Thread t = Thread.currentThread();
        setBlocker(t, blocker);
        unsafe.park(true, deadline);
        setBlocker(t, null);
    }
    public static Object getBlocker(Thread t) {
        if (t == null)
            throw new NullPointerException();
        return unsafe.getObjectVolatile(t, parkBlockerOffset);
    }
    public static void park() {
        unsafe.park(false, 0L);
    }
    public static void parkNanos(long nanos) {
        if (nanos > 0)
            unsafe.park(false, nanos);
    }
    public static void parkUntil(long deadline) {
        unsafe.park(true, deadline);
    }
}
?

解读源码

  • LockSupport不可被实例化(因为构造函数是私有的)
  • LockSupport中有两个私有变量unsafeparkBlockerOffset;
  • LockSupport的方法都是静态方法

?

二:深入分析@变量

?

??? 先来看一下其成员变量:

???
 // Hotspot implementation via intrinsics API
    private static final Unsafe unsafe = Unsafe.getUnsafe();
    private static final long parkBlockerOffset;
?

unsafe:全名sun.misc.Unsafe用于可以直接操控内存,被JDK广泛用于自己的包中,如java.niojava.util.concurrent但是丝毫不建议在生产环境中使用这个类。因为这个API十分不安全、不轻便、而且不稳定。这个不安全的类提供了一个观察HotSpot JVM内部结构并且可以对其进行修改。有时它可以被用来在不适用C++调试的情况下学习虚拟机内部结构,有时也可以被拿来做性能监控和开发工具。

parkBlockerOffset字面理解为parkBlocker的偏移量,但是parkBlocker又是干嘛的?偏移量又是做什么的呢?

?

1.关于parkBlocker

java.lang.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;
?

从注释上看,这个对象被LockSupportsetBlockergetBlocker调用。查看JAVADOC会发现这么一段解释:
bubuko.com,布布扣
?

大致意思是,这个对象是用来记录线程被阻塞时被谁阻塞的,用于线程监控和分析工具来定位原因的。

原来parkBlocker是用于记录线程是被谁阻塞的。可以通过LockSupportgetBlocker获取到阻塞的对象。主要用于监控和分析线程用的。

?

2:关于parkBlockerOffset

    static {
        try {
            parkBlockerOffset = unsafe.objectFieldOffset
                (java.lang.Thread.class.getDeclaredField("parkBlocker"));
        } catch (Exception ex) { throw new Error(ex); }
    }

?? 我们把这段代码拆解一下:

?????? Field field = java.lang.Thread.class.getDeclaredField("parkBlocker");

?????? parkBlockerOffset = unsafe.objectFieldOffset(field);

?

???? 从这个静态语句块可以看的出来,先是通过反射机制获取Thread类的parkBlocker字段对象。然后通过sun.misc.Unsafe对象的objectFieldOffset方法获取到parkBlocker在内存里的偏移量,parkBlockerOffset的值就是这么来的.

JVM的实现可以自由选择如何实现Java对象的布局,也就是在内存里Java对象的各个部分放在哪里,包括对象的实例字段和一些元数据之类。 sun.misc.Unsafe里关于对象字段访问的方法把对象布局抽象出来,它提供了objectFieldOffset()方法用于获取某个字段相对 Java对象的起始地址的偏移量,也提供了getIntgetLonggetObject之类的方法可以使用前面获取的偏移量来访问某个Java 对象的某个字段。

?

3:为什么要用偏移量来获取对象?干吗不要直接写个getset方法。多简单?

仔细想想就能明白,这个parkBlocker就是在线程处于阻塞的情况下才会被赋值。线程都已经阻塞了,如果不通过这种内存的方法,而是直接调用线程内的方法,线程是不会回应调用的。

?

三:深入分析@方法

??? 查看源码,你会发现LockSupport中有且只有一个私有方法

   private static void setBlocker(Thread t, Object arg) {
        // Even though volatile, hotspot doesn‘t need a write barrier here.
        unsafe.putObject(t, parkBlockerOffset, arg);
    }

??? 解读:对给定线程tparkBlocker赋值。为了防止这个parkBlocker被误用,该方法是不对外公开的。

?

????

    public static Object getBlocker(Thread t) {
        if (t == null)
            throw new NullPointerException();
        return unsafe.getObjectVolatile(t, parkBlockerOffset);
    }
? ?解读:从线程t中获取它的parkBlocker对象,即返回的是阻塞线程tBlocker对象。?

?

?

接下来的方法里可以分两类,一类是以park开头的方法,用于阻塞线程:

??

 publicstaticvoid park(Object blocker) {
        Thread t = Thread.currentThread();
        setBlocker(t, blocker);
        unsafe.park(false, 0L);
        setBlocker(t, null);
    }
    publicstaticvoid parkNanos(Object blocker, long nanos) {
        if (nanos > 0) {
            Thread t = Thread.currentThread();
            setBlocker(t, blocker);
            unsafe.park(false, nanos);
            setBlocker(t, null);
        }
    }
    publicstaticvoid parkUntil(Object blocker, long deadline) {
        Thread t = Thread.currentThread();
        setBlocker(t, blocker);
        unsafe.park(true, deadline);
        setBlocker(t, null);
    }
    publicstaticvoid park() {
        unsafe.park(false, 0L);
    }
    publicstaticvoid parkNanos(long nanos) {
        if (nanos > 0)
            unsafe.park(false, nanos);
    }
    publicstaticvoid parkUntil(long deadline) {
        unsafe.park(true, deadline);
    }

?

?

?

一类是以unpark开头的方法,用于解除阻塞:

    public static void unpark(Thread thread) {
        if (thread != null)
            unsafe.unpark(thread);
    }
?

?

?

?

参考资料:

?? http://my.oschina.net/readjava/blog/282882

?? JDK源码

?? JDK API文档

??

LockSupport详解 | Java并发编程

原文:http://15838341661-139-com.iteye.com/blog/2239748

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!