继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

[Java源码][并发J.U.C]---LockSupport

青春有我
关注TA
已关注
手记 1199
粉丝 205
获赞 1008

前言

本篇文章主要分析LockSupport,在系列文章中的AQS就有用到. 本文会通过源码分析中看看LockSupport如何使用.

本文代码: 代码下载

LockSupport源码

LockSupportjava.util.concurrent.locks包中,总共的代码就一两百行左右,如下:

import java.lang.reflect.Field;import sun.misc.Unsafe;public class LockSupport {    
    private LockSupport() {} 

    private static void setBlocker(Thread t, Object arg) {
        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);
    }    
    static final int nextSecondarySeed() {        int r;
        Thread t = Thread.currentThread();        if ((r = UNSAFE.getInt(t, SECONDARY)) != 0) {
            r ^= r << 13;   // xorshift
            r ^= r >>> 17;
            r ^= r << 5;
        }        else if ((r = java.util.concurrent.ThreadLocalRandom.current().nextInt()) == 0)
            r = 1; // avoid zero
        UNSAFE.putInt(t, SECONDARY, r);        return r;
    }    // Hotspot implementation via intrinsics API
    private static final sun.misc.Unsafe UNSAFE;    private static final long parkBlockerOffset;    private static final long SEED;    private static final long PROBE;    private static final long SECONDARY;    static {        try {    //UNSAFE = sun.misc.Unsafe.getUnsafe(); 源码
                Field f = Unsafe.class.getDeclaredField("theUnsafe");
                f.setAccessible(true);
                UNSAFE = (Unsafe)f.get(null);
                
            Class<?> tk = Thread.class;
            parkBlockerOffset = UNSAFE.objectFieldOffset
                (tk.getDeclaredField("parkBlocker"));
            SEED = UNSAFE.objectFieldOffset
                (tk.getDeclaredField("threadLocalRandomSeed"));
            PROBE = UNSAFE.objectFieldOffset
                (tk.getDeclaredField("threadLocalRandomProbe"));
            SECONDARY = UNSAFE.objectFieldOffset
                (tk.getDeclaredField("threadLocalRandomSecondarySeed"));
        } catch (Exception ex) { throw new Error(ex); }
    }
}

代码中只有在获得UNSAFE的时候改成了反射实现,其余的都是维持原样.因为需要有特定的classloader才可以加载Unsafe类,因此在自己的代码中用反射来拿到实例对象.
另外Unsafe类的作用会有专门博客分析,暂时可以认为该类可以利用底层的方法成功操作.
注意: tkThread.class,操作的是Thread类的成员变量.

从上面源码中可以看到:

1. 只有一个构造方法并且还是私有的,所以没办法new出一个对象.
2. 方法几乎都是静态的,所以通过类就可以调用.
3.  所有的park*方法最终都会调用UNSAFE.park(boolean, long)方法,unpark最终还是会调用UNSAFE.unpark(Thread)方法.
4.  有一个setBlockergetBlocker方法.

所以从该源码中也具体看不出逻辑和实现,所以看看Unsafeparkunpark方法.

sun.misc.Unsafe中的parkunpark

sun.misc.Unsafe中的源码

public native void unpark(Object paramObject);public native void park(boolean paramBoolean, long paramLong);

这个是本地方法,实现如下:

源码在park.hpp(这个是1.7的,没有找到1.8的,有地址,但是还是没有找到具体的类的位置)
每个线程都有一个Parker实例,每个实例有一个_counter属性,初始化值为0.

webp

图片.png

对应的parkunpark源码, 源码文件

park方法

webp

图片.png

isAbsolute表示是否是绝对时间,可以看到parkUntil(long deadline)调用的时候表示的是绝对时间

1. 如果_counter变量大于0,便可以获得许可permit.
2. 可选性的优化,在阻塞前检查一下中断状态.如果当前线程处于中断状态,则直接返回._counter没有变化,此时的_counter处于
3. 检查一下时间是否到时,比如那种超时获取许可的方法等,另外如果time > 0,则调用unpackTime(&absTime, isAbsolute, time);方法

webp

图片.png

4.  生成一个ThreadBlockInVM
5.  这句话我还没有弄明白
6.  再次检查_counter是不是大于0,如果是的话表示可以获得许可并且把_counter并且unlock _mutex.

webp

图片.png



作者:nicktming
链接:https://www.jianshu.com/p/ca3e8a5b7a1d


打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP