`
周凡杨
  • 浏览: 234807 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

LockSupport详解 | Java并发编程

阅读更多
 

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

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会发现这么一段解释:

 

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

原来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文档

  

  • 大小: 105.3 KB
0
1
分享到:
评论

相关推荐

    Java并发编程之LockSupport、Unsafe详解.docx

    在Java并发编程中,LockSupport和Unsafe是两个关键的工具类,它们提供了底层的线程控制功能,使得开发者能够深入地管理和控制线程的行为。LockSupport是Java并发库中的一个核心工具类,它提供了线程的阻塞和唤醒功能...

    Java并发编程笔记

    ### Java并发编程知识点详解 #### 一、线程状态与管理 在Java中,线程具有多种状态,这些状态的变化反映了线程在其生命周期中的不同阶段。理解这些状态及其转换对于编写高效、健壮的并发程序至关重要。 - **NEW**...

    Java 多线程与并发(9-26)-JUC锁- LockSupport详解.pdf

    这个类位于java.util.concurrent.locks包下,是实现并发编程中AQS(AbstractQueuedSynchronizer)框架的重要基础之一。LockSupport的目的是为了简化锁和其他同步类的实现,允许开发者创建更加高级的并发工具。 ...

    Java并发编程线程间通讯实现过程详解

    "Java并发编程线程间通讯实现过程详解" Java并发编程线程间通讯实现过程详解是Java编程中非常重要的一部分,涉及到多线程之间的数据共享、同步和通信。在Java中,线程间通讯可以通过多种方式实现,本文将通过示例...

    Java并发编程学习之Unsafe类与LockSupport类源码详析

    《深入解析Java并发编程:Unsafe类与LockSupport类源码剖析》 在Java并发编程领域,Unsafe类和LockSupport类是两个重要的底层工具类,它们提供了低级别的内存操作和线程控制,使得开发者能够实现高效的并发算法和...

    大并发编程交流

    ### 大并发编程交流知识点详解 #### 一、并发编程基础与重要性 并发编程是在计算机科学领域中处理多个任务同时执行的一种技术。随着多核处理器的普及以及互联网应用复杂性的增加,对并发编程的需求日益增长。良好...

    【2018最新最详细】并发多线程教程

    1.并发编程的优缺点 2.线程的状态转换以及基本操作 3.java内存模型以及happens-before规则 4.彻底理解synchronized 5.彻底理解volatile 6.你以为你真的了解final吗? 7.三大性质总结:原子性、可见性以及有序性 8....

    详解Java多线程编程中LockSupport类的线程阻塞用法

    在Java多线程编程中,LockSupport类是一个重要的工具,它提供了一种低级别的线程阻塞和唤醒机制。LockSupport并不像synchronized或java.util.concurrent.locks包中的Lock接口那样提供锁的完整功能,但它提供了两个...

    Java多线程和并发知识整理

    JUC锁: LockSupport详解** LockSupport是线程阻塞和唤醒的基础,用于构建锁和其他同步组件。 以上内容涵盖了Java多线程和并发编程的主要知识点,从理论到实践,从基础到高级,全面解析了并发编程的核心概念和工具...

    java+多线程+同步详解Java源码

    综上所述,Java的多线程和同步机制是实现并发编程的基础,通过合理利用这些机制,开发者可以编写出高效、安全的多线程应用程序。在实际工作中,不仅需要理解这些概念,还要能够熟练地应用到项目中,解决多线程环境下...

    Java多线程编程总结

    ### Java多线程编程知识点详解 #### 一、Java线程:概念与原理 Java多线程编程的核心在于理解和利用操作系统中的线程和进程概念。**进程**是系统进行资源分配和调度的基本单位,每个进程拥有独立的内存空间。而**...

    java-concurrency-in-practice:java并发精讲

    通过以上内容,我们可以对Java并发编程有一个全面的认识,从创建线程到管理线程,再到处理并发问题,每一步都需要精心设计和严谨实现。在实际项目中,理解并熟练运用这些概念和技术,能够构建出高效、稳定的并发应用...

    java的Lock锁原理详解.docx

    Java中的锁机制是多线程编程中至关重要的一个概念,用于协调多个线程对共享资源的访问。在Java中,有两种主要的锁机制:synchronized和Lock。它们都是用来实现线程同步,防止数据竞争,确保并发环境下的数据一致性。...

    Java多线程超级详解(看这篇就足够了).pdf

    Java多线程是Java编程中不可或缺的一部分,它允许程序同时执行多个任务,从而提升程序的运行效率和响应速度。在高并发环境下,掌握多线程技术对于开发高性能的应用至关重要。本篇文章将深入探讨Java多线程的基本概念...

    java Thread

    【Java线程详解】 在Java编程中,线程(Thread)是...同时,理解JVM对线程的调度以及线程安全问题的处理也是提升Java并发编程能力的关键。在实际开发中,应结合具体需求灵活运用各种线程控制手段,以实现最佳性能。

    java 中死锁问题的实例详解

    Java中的死锁问题是一个复杂但重要的并发编程概念。死锁是指两个或多个并发执行的线程因争夺资源而造成的一种相互等待的现象,若无外力干涉它们都无法推进下去。在这个实例中,我们将深入理解死锁的产生原因以及如何...

    Java多线程 线程状态原理详解

    Java多线程是并发编程中的核心概念,它允许程序同时执行多个任务,从而提升系统效率。线程状态的理解对于编写高效、稳定的并发程序至关重要。在Java中,`java.lang.Thread.State`枚举类定义了线程的六种状态,分别是...

    java程序员面试大纲错过了金三银四你还要错过2018吗.docx

    #### 三、Java并发编程 1. **synchronized的实现原理**:通过内置锁(监视器锁)实现同步控制,当一个线程获取到锁后,其他线程必须等待锁释放才能继续执行。 2. **volatile的实现原理**:`volatile`关键字确保变量...

    类似Object监视器方法的Condition接口(详解)

    在Java并发编程中,`Condition`接口是一个非常重要的概念,它提供了类似于`Object`类的监视器方法(如`wait()`、`notify()`和`notifyAll()`),但具有更高的灵活性。`Condition`接口是Java `java.util.concurrent....

Global site tag (gtag.js) - Google Analytics