LockSupport 以及 park、unpark 方法源码分析(上)

简介: LockSupport是 jsr 166 中新增的 juc 工具类。 LockSupport 类主要用于创建锁和其他同步类来实现线程阻塞。 这个类与他使用的每个线程进行关联, 如果可用就立即 park , 我们可以通过 unpack 方法进行唤醒。

LockSupport


是 jsr 166 中新增的 juc 工具类。 LockSupport 类主要用于创建锁和其他同步类来实现线程阻塞。 这个类与他使用的每个线程进行关联, 如果可用就立即 park , 我们可以通过 unpack 方法进行唤醒。


park 方法分析


除非许可证可用,否则出于线程调度目的禁用当前线程。 如果许可证可用,则该许可证被消耗,呼叫立即返回;否则,出于线程调度目的,当前线程将被禁用,并处于休眠状态,直到发生以下三种情况之一:


  • 其他线程以当前线程为目标调用 unpark;


  • 或其他线程中断当前线程;


  • 或呼叫错误地(即,没有原因地)返回。


此方法不报告导致方法返回的原因。调用方应首先重新检查导致线程停止的条件。调用方还可以在返回时确定线程的中断状态。


public static void park(Object blocker) {
    Thread t = Thread.currentThread();
    setBlocker(t, blocker);
    UNSAFE.park(false, 0L);
    setBlocker(t, null);
}


unpark 方法分析


使给定线程的许可证可用(如果尚未可用)。如果线程在 park上被阻塞,那么它将解除阻塞。否则,它对 park 的下一次呼叫保证不会被阻塞。如果给定的线程尚未启动,则不能保证此操作有任何效果。


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


JVM 源码分析


park 方法源码分析


通过上面的代码我们可以看到,在 LockSupport 的底层主要是调用 Unsafa 类的 park, unpark 方法实现(源码文件:unsafe.cpp链接):


UNSAFE_ENTRY(void, Unsafe_Park(JNIEnv *env, jobject unsafe, jboolean isAbsolute, jlong time))
  UnsafeWrapper("Unsafe_Park");
  EventThreadPark event;
#ifndef USDT2
  HS_DTRACE_PROBE3(hotspot, thread__park__begin, thread->parker(), (int) isAbsolute, time);
#else /* USDT2 */
   HOTSPOT_THREAD_PARK_BEGIN(
                             (uintptr_t) thread->parker(), (int) isAbsolute, time);
#endif /* USDT2 */
  JavaThreadParkedState jtps(thread, time != 0);
  thread->parker()->park(isAbsolute != 0, time);
#ifndef USDT2
  HS_DTRACE_PROBE1(hotspot, thread__park__end, thread->parker());
#else /* USDT2 */
  HOTSPOT_THREAD_PARK_END(
                          (uintptr_t) thread->parker());
#endif /* USDT2 */
  if (event.should_commit()) {
    oop obj = thread->current_park_blocker();
    event.set_klass((obj != NULL) ? obj->klass() : NULL);
    event.set_timeout(time);
    event.set_address((obj != NULL) ? (TYPE_ADDRESS) cast_from_oop<uintptr_t>(obj) : 0);
    event.commit();
  }
UNSAFE_END
UNSAFE_ENTRY(void, Unsafe_Unpark(JNIEnv *env, jobject unsafe, jobject jthread))
  UnsafeWrapper("Unsafe_Unpark");
  Parker* p = NULL;
  if (jthread != NULL) {
    oop java_thread = JNIHandles::resolve_non_null(jthread);
    if (java_thread != NULL) {
      jlong lp = java_lang_Thread::park_event(java_thread);
      if (lp != 0) {
        // This cast is OK even though the jlong might have been read
        // non-atomically on 32bit systems, since there, one word will
        // always be zero anyway and the value set is always the same
        p = (Parker*)addr_from_java(lp);
      } else {
        // Grab lock if apparently null or using older version of library
        MutexLocker mu(Threads_lock);
        java_thread = JNIHandles::resolve_non_null(jthread);
        if (java_thread != NULL) {
          JavaThread* thr = java_lang_Thread::thread(java_thread);
          if (thr != NULL) {
            p = thr->parker();
            if (p != NULL) { // Bind to Java thread for next time.
              java_lang_Thread::set_park_event(java_thread, addr_to_java(p));
            }
          }
        }
      }
    }
  }
  if (p != NULL) {
#ifndef USDT2
    HS_DTRACE_PROBE1(hotspot, thread__unpark, p);
#else /* USDT2 */
    HOTSPOT_THREAD_UNPARK(
                          (uintptr_t) p);
#endif /* USDT2 */
    p->unpark();
  }
UNSAFE_END


每个线程对象都有一个 Parker 实例(源码文件:thread.hpp


// JSR166 per-thread parker
private:
  Parker*    _parker;
public:
  Parker*     parker() { return _parker; }


parker 类的定义如下,我们可以看到(源码文件 park.hpp)。


  1. Parker 类继承 os::PlatformParker。 应该是一个针对不同操作系统适配的


  1. 有一个 _counter 属性,可以理解为是否可以调用 park 方法的许可证,只有 _count > 0 的时候才能调用;


  1. 提供了公开的  park 和 unpark 方法


class Parker : public os::PlatformParker {
private:
  volatile int _counter ;
  Parker * FreeNext ;
  JavaThread * AssociatedWith ; // Current association
public:
  Parker() : PlatformParker() {
    _counter       = 0 ;
    FreeNext       = NULL ;
    AssociatedWith = NULL ;
  }
protected:
  ~Parker() { ShouldNotReachHere(); }
public:
  // For simplicity of interface with Java, all forms of park (indefinite,
  // relative, and absolute) are multiplexed into one call.
  void park(bool isAbsolute, jlong time);
  void unpark();
  // Lifecycle operators
  static Parker * Allocate (JavaThread * t) ;
  static void Release (Parker * e) ;
private:
  static Parker * volatile FreeList ;
  static volatile int ListLock ;
};


前面我提到 Parker 的父类是 PlatformParker (源码文件 os_linux.cpp)。 我们可以看下他在 Linunx 下 Parker 的 park 方法的实现过程:


  1. 判断是否需要阻塞等待,如果已经是 _counter >0, 不需要等待,将 _counter = 0 , 返回


  1. 如果 1 不成立,构造当前线程的 ThreadBlockInVM ,检查 _counter > 0 是否成立,成立则将 _counter 设置为 0, unlock mutex 返回;


  1. 如果 2 不成立,更具需要时间进行不同的函数等待,如果等待正确返回,则将 _counter 设置为0, unlock mutex , park 调用成功。


相关文章
|
安全 Java 程序员
如何理解并使用 park 与 unpark
park和unpark是Java中的两个线程同步工具,用于线程的阻塞和唤醒操作。
389 0
如何理解并使用 park 与 unpark
【多线程:Park&Unpark】
【多线程:Park&Unpark】
95 0
|
分布式计算 Spark Java
Spark2.4.0 SparkSession 源码分析
创建SparkContext new SparkSession
3277 0
|
Java
LockSupport 以及 park、unpark 方法源码分析(下)
LockSupport 是 jsr 166 中新增的 juc 工具类。 LockSupport 类主要用于创建锁和其他同步类来实现线程阻塞。 这个类与他使用的每个线程进行关联, 如果可用就立即 park , 我们可以通过 unpack 方法进行唤醒。
356 0
|
存储 分布式计算 大数据
Spark中几种ShuffleWriter的区别你都知道吗?
一.前言 在Spark中有三种shuffle写,分别是BypassMergeSortShuffleWriter、UnsafeShuffleWriter、SortShuffleWriter。分别对应三种不同的shuffleHandle。
1345 0
|
分布式计算 Spark 索引
Spark2.4.0源码分析之WorldCount ShuffleMapTask处理(八)
- 理解Executor中是如何调用Task的过程 - 理解ShuffleMapTask是处理过程
1620 0
|
调度 算法
Spark2.4.0源码分析之WorldCount 任务调度器(七)
- 理解TaskSet是如何提交到任务调度器池,任务集如何被调度 - 理解Worker可用资源算法,Worker可用资源分配任务调度池中的任务 - 任务发送给executor去执行
897 0
|
分布式计算 Spark
Spark2.4.0 SparkEnv 源码分析
SparkEnv对象构建 SparkEnv类中做如下操作 ).new SecurityManager() ).new NettyRpcEnvFactory() ).创建NettyRpcEnv ).
1754 0
|
分布式计算 资源调度 调度
Spark2.4.0 SparkContext 源码分析
createSparkEnv Started SparkUI 注册端点HeartbeatReceiver createTaskScheduler 启动任务调度器,指定默认任务调度模式FIFO,构建调度池 new DAGScheduler 注册DriverEndpoint端点:Coarse...
2953 0
|
分布式计算 Spark Hadoop
Spark MapOutputTracker源码分析
## 技能标签 - Spark ShuffleMapTask处理完成后,把MapStatus数据(BlockManagerId,[compressSize])发送给MapOutputTrackerMaster.
1693 0