我们一再提线程、锁等概念,但锁是如果实现的呢?又是如何知道当前阻塞线程的又是哪个对象呢?
从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中有两个私有变量unsafe和parkBlockerOffset;
- LockSupport的方法都是静态方法
二:深入分析@变量
先来看一下其成员变量:
// Hotspot implementation via intrinsics API private static final Unsafe unsafe = Unsafe.getUnsafe(); private static final long parkBlockerOffset;
unsafe:全名sun.misc.Unsafe用于可以直接操控内存,被JDK广泛用于自己的包中,如java.nio和java.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;
从注释上看,这个对象被LockSupport的setBlocker和getBlocker调用。查看JAVADOC会发现这么一段解释:
大致意思是,这个对象是用来记录线程被阻塞时被谁阻塞的,用于线程监控和分析工具来定位原因的。
原来parkBlocker是用于记录线程是被谁阻塞的。可以通过LockSupport的getBlocker获取到阻塞的对象。主要用于监控和分析线程用的。
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对象的“起始地址”的偏移量,也提供了getInt、getLong、getObject之类的方法可以使用前面获取的偏移量来访问某个Java 对象的某个字段。
3:为什么要用偏移量来获取对象?干吗不要直接写个get,set方法。多简单?
仔细想想就能明白,这个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); }
解读:对给定线程t的parkBlocker赋值。为了防止这个parkBlocker被误用,该方法是不对外公开的。
public static Object getBlocker(Thread t) { if (t == null) throw new NullPointerException(); return unsafe.getObjectVolatile(t, parkBlockerOffset); }解读:从线程t中获取它的parkBlocker对象,即返回的是阻塞线程t的Blocker对象。
接下来的方法里可以分两类,一类是以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文档
相关推荐
Java 多线程与并发(9_26)-JUC锁_ LockSupport详解
在Java多线程中,当需要阻塞或者唤醒一个线程时,都会使用LockSupport工具类来完成相应的工作。LockSupport定义了一组公共静态方法,这些方法提供了最基本的线程阻塞和唤醒功能,而LockSupport也因此成为了构建同步...
主要给大家介绍了关于Java并发编程学习之Unsafe类与LockSupport类源码的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面来一起看看吧
LockSupport类提供了park()和unpark()两个方法来实现线程的阻塞和唤醒,下面我们就来详解Java多线程编程中LockSupport类的线程阻塞用法:
1.并发编程的优缺点 2.线程的状态转换以及基本操作 3.java内存模型以及happens-before规则 4.彻底理解synchronized 5.彻底理解volatile 6.你以为你真的了解final吗? 7.三大性质总结:原子性、可见性以及有序性 8....
一、理论基础 1.1为什么需要多线程 1.2不安全示例 1.3并发问题的根源 1.4JMM 1.5线程安全的分类 1.6线程安全的方法 二、线程基础 2.1状态 2.2使用方式 2.3基础机制 ...十一、JUC锁: LockSupport详解
LockSupport是JDK1.6中在java.util.concurrent中的子包locks中引入的一个比较底层的工具类,用来创建锁和其他同步工具类的基本线程阻塞原语。java锁和同步器框架的核心 AQS: AbstractQueuedSynchronizer,就是通过...
Java并发包源码分析(JDK1.8):囊括了java.util.concurrent包中大部分类的源码分析,其中涉及automic包,locks包...对每个类的核心源码进行详细分析,笔记详细,由浅入深,层层深入,带您剖析并发编程原理
LockSupport.xmid总结,用于知识巩固,
主要为大家详细介绍了Java concurrency之LockSupport的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
本文将详细介绍java线程阻塞中断和LockSupport的使用,需要了解更多的朋友可以参考下
并发编程专题 Executors线程池 线程池ThreadPoolExecutor 并发编程 Lock 锁 Lock 可重入锁Reetrantlock 可重入读写锁ReetrantReadWriteLock Condition ReadWriteLock LockSupport 并发类编程工具 CountDownLatch ...
面试高级开发的期间整理的面试题目,记录我面试遇到过的并发题目以及答案 目录 并发 常说的并发问题是哪些;资源竞争、死锁、事务、可见性 死锁 如何排查死锁; 产生死锁的必要条件: 如何解决解决死锁; 锁 AQS:...
AQS 原理 ...LockSupport.park() 完成,而 LockSupport.park() 则调用 sun.misc.Unsafe.park()本地方法,再进一步,HotSpot 在 Linux 中中通过调用 pthread_mutex_lock 函数把线程交给系统内核进行阻塞。
java并发,主要用于初学者学习,主要案列,Thread.join,ThreadLocal,Lock接口,LockSupport,Condition接口,ConcurrentHashMap的实现原理与使用 Fork/Join 框架,CountDownLatch,CyclicBarrier,Semaphore,...
LockSupport学习demoLockSupport学习demoLockSupport学习demoLockSupport学习demoLockSupport学习demoLockSupport学习demoLockSupport学习demoLockSupport学习demoLockSupport学习demoLockSupport学习...
一. 1.创建线程: (1)在创建线程时,传入Runnable接口的实现类,重写run方法指定执行任务 (2)使用FutureTask(实现Runnable接口)来指定任务,可以通过get方法来获得执行...(5)Park:LockSupport的静态方法,在调用时会
使用 LockSupport.park()and unpark() public static void main(String[] args) { char[] aI = 1234567.toCharArray(); char[] aC = ABCDEFG.toCharArray(); Lock lock = new ReentrantLock(); Condition
测试LockSupport,LockSupport基于一个“许可”的概念实现了线程的阻塞与释放,该测试demo就是为了使这个“许可”的概念更加的清晰