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

Java Unsafe-park/unpark操作

 
阅读更多

park/unpark操作

这两个操作通常配合在一起使用,park操作用于阻塞当前线程,unpark用于使阻塞在park操作代码处的线程退出阻塞。

 

park操作

 

Block current thread, returning when a balancing

<tt>unpark</tt> occurs, or a balancing <tt>unpark</tt> has

already occurred, or the thread is interrupted, or, if not

absolute and time is not zero, the given time nanoseconds have

elapsed, or if absolute, the given deadline in milliseconds

since Epoch has passed, or spuriously (i.e., returning for no

"reason"). Note: This operation is in the Unsafe class only

because <tt>unpark</tt> is, so it would be strange to place it

elsewhere.

 

该方法是一个native方法:

public native void park(boolean isAbsolute, long time);

该方法实现unsafe.cpp在\hotspot\src\share\vm\prims目录下。

UNSAFE_ENTRY(void, Unsafe_Park(JNIEnv *env, jobject unsafe, jboolean isAbsolute, jlong time))

  UnsafeWrapper("Unsafe_Park");

#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 */

UNSAFE_END

以上代码需要展开来才能看得懂,展开后代码如下:

如果定义了USDT2宏

UNSAFE_ENTRY(void, Unsafe_Park(JNIEnv *env, jobject unsafe, jboolean isAbsolute, jlong time))
  UnsafeWrapper("Unsafe_Park");
  HOTSPOT_THREAD_PARK_BEGIN(
                             (uintptr_t) thread->parker(), (int) isAbsolute, time);
  JavaThreadParkedState jtps(thread, time != 0);
  thread->parker()->park(isAbsolute != 0, time);
  HOTSPOT_THREAD_PARK_END(
                          (uintptr_t) thread->parker());
UNSAFE_END

 

#define HOTSPOT_THREAD_PARK_BEGIN(arg0, arg1, arg2)

 

#define HOTSPOT_THREAD_PARK_END(arg0)

 

 

extern "C" {                                                        

  void JNICALL Unsafe_Park(JNIEnv *env, jobject unsafe, jboolean isAbsolute, jlong time) {                                      

    JavaThread* thread=JavaThread::thread_from_jni_environment(env);

    ThreadInVMfromNative __tiv(thread);

 

    /* do nothing */

 

    HandleMarkCleaner __hm(thread);                                   

    Thread* THREAD = thread;

 

    /* begin of body */

 

    /*nothing, for the present*/;

 

    ;

    JavaThreadParkedState jtps(thread, time != 0);

    thread->parker()->park(isAbsolute != 0, time);

    ;

  }

}

 

如果没有定义USDT2宏

UNSAFE_ENTRY(void, Unsafe_Park(JNIEnv *env, jobject unsafe, jboolean isAbsolute, jlong time))
  UnsafeWrapper("Unsafe_Park");
  HS_DTRACE_PROBE3(hotspot, thread__park__begin, thread->parker(), (int) isAbsolute, time);
  JavaThreadParkedState jtps(thread, time != 0);
  thread->parker()->park(isAbsolute != 0, time);
  HOTSPOT_THREAD_PARK_END(
                          (uintptr_t) thread->parker());
UNSAFE_END

 

 

这里不展开USDT2宏没有定义的那段代码

 

其中主要的代码在:

thread->parker()->park(isAbsolute != 0, time);

 

solaris平台下这块代码实现在os_solaris.cpp,在\hotspot\src\os\solaris\vm目录下。

void Parker::park(bool isAbsolute, jlong time) {

 

  // Optional fast-path check:

  // Return immediately if a permit is available.

  if (_counter > 0) {

      _counter = 0 ;

      OrderAccess::fence();

      return ;

  }

 

  // Optional fast-exit: Check interrupt before trying to wait

  Thread* thread = Thread::current();

  assert(thread->is_Java_thread(), "Must be JavaThread");

  JavaThread *jt = (JavaThread *)thread;

  if (Thread::is_interrupted(thread, false)) {

    return;

  }

 

  // First, demultiplex/decode time arguments

  timespec absTime;

  if (time < 0 || (isAbsolute && time == 0) ) { // don't wait at all

    return;

  }

  if (time > 0) {

    // Warning: this code might be exposed to the old Solaris time

    // round-down bugs.  Grep "roundingFix" for details.

    unpackTime(&absTime, isAbsolute, time);

  }

 

  // Enter safepoint region

  // Beware of deadlocks such as 6317397.

  // The per-thread Parker:: _mutex is a classic leaf-lock.

  // In particular a thread must never block on the Threads_lock while

  // holding the Parker:: mutex.  If safepoints are pending both the

  // the ThreadBlockInVM() CTOR and DTOR may grab Threads_lock.

  ThreadBlockInVM tbivm(jt);

 

  // Don't wait if cannot get lock since interference arises from

  // unblocking.  Also. check interrupt before trying wait

  if (Thread::is_interrupted(thread, false) ||

      os::Solaris::mutex_trylock(_mutex) != 0) {

    return;

  }

 

  int status ;

 

  if (_counter > 0)  { // no wait needed

    _counter = 0;

    status = os::Solaris::mutex_unlock(_mutex);

    assert (status == 0, "invariant") ;

    OrderAccess::fence();

    return;

  }

 

#ifdef ASSERT

  // Don't catch signals while blocked; let the running threads have the signals.

  // (This allows a debugger to break into the running thread.)

  sigset_t oldsigs;

  sigset_t* allowdebug_blocked = os::Solaris::allowdebug_blocked_signals();

  thr_sigsetmask(SIG_BLOCK, allowdebug_blocked, &oldsigs);

#endif

 

  OSThreadWaitState osts(thread->osthread(), false /* not Object.wait() */);

  jt->set_suspend_equivalent();

  // cleared by handle_special_suspend_equivalent_condition() or java_suspend_self()

 

  // Do this the hard way by blocking ...

  // See http://monaco.sfbay/detail.jsf?cr=5094058.

  // TODO-FIXME: for Solaris SPARC set fprs.FEF=0 prior to parking.

  // Only for SPARC >= V8PlusA

#if defined(__sparc) && defined(COMPILER2)

  if (ClearFPUAtPark) { _mark_fpu_nosave() ; }

#endif

 

  if (time == 0) {

    status = os::Solaris::cond_wait (_cond, _mutex) ;

  } else {

    status = os::Solaris::cond_timedwait (_cond, _mutex, &absTime);

  }

  // Note that an untimed cond_wait() can sometimes return ETIME on older

  // versions of the Solaris.

  assert_status(status == 0 || status == EINTR ||

                status == ETIME || status == ETIMEDOUT,

                status, "cond_timedwait");

 

#ifdef ASSERT

  thr_sigsetmask(SIG_SETMASK, &oldsigs, NULL);

#endif

  _counter = 0 ;

  status = os::Solaris::mutex_unlock(_mutex);

  assert_status(status == 0, status, "mutex_unlock") ;

 

  // If externally suspended while waiting, re-suspend

  if (jt->handle_special_suspend_equivalent_condition()) {

    jt->java_suspend_self();

  }

  OrderAccess::fence();

}

 

 

 

linux平台下这块代码实现在os_linux.cpp,在hotspot\src\os\linux\vm目录下。

void Parker::park(bool isAbsolute, jlong time) {
  // Optional fast-path check:
  // Return immediately if a permit is available.
  if (_counter > 0) {
      _counter = 0 ;
      OrderAccess::fence();
      return ;
  }

  Thread* thread = Thread::current();
  assert(thread->is_Java_thread(), "Must be JavaThread");
  JavaThread *jt = (JavaThread *)thread;

  // Optional optimization -- avoid state transitions if there's an interrupt pending.
  // Check interrupt before trying to wait
  if (Thread::is_interrupted(thread, false)) {
    return;
  }

  // Next, demultiplex/decode time arguments
  timespec absTime;
  if (time < 0 || (isAbsolute && time == 0) ) { // don't wait at all
    return;
  }
  if (time > 0) {
    unpackTime(&absTime, isAbsolute, time);
  }


  // Enter safepoint region
  // Beware of deadlocks such as 6317397.
  // The per-thread Parker:: mutex is a classic leaf-lock.
  // In particular a thread must never block on the Threads_lock while
  // holding the Parker:: mutex.  If safepoints are pending both the
  // the ThreadBlockInVM() CTOR and DTOR may grab Threads_lock.
  ThreadBlockInVM tbivm(jt);

  // Don't wait if cannot get lock since interference arises from
  // unblocking.  Also. check interrupt before trying wait
  if (Thread::is_interrupted(thread, false) || pthread_mutex_trylock(_mutex) != 0) {
    return;
  }

  int status ;
  if (_counter > 0)  { // no wait needed
    _counter = 0;
    status = pthread_mutex_unlock(_mutex);
    assert (status == 0, "invariant") ;
    OrderAccess::fence();
    return;
  }

#ifdef ASSERT
  // Don't catch signals while blocked; let the running threads have the signals.
  // (This allows a debugger to break into the running thread.)
  sigset_t oldsigs;
  sigset_t* allowdebug_blocked = os::Linux::allowdebug_blocked_signals();
  pthread_sigmask(SIG_BLOCK, allowdebug_blocked, &oldsigs);
#endif

  OSThreadWaitState osts(thread->osthread(), false /* not Object.wait() */);
  jt->set_suspend_equivalent();
  // cleared by handle_special_suspend_equivalent_condition() or java_suspend_self()

  if (time == 0) {
    status = pthread_cond_wait (_cond, _mutex) ;
  } else {
    status = os::Linux::safe_cond_timedwait (_cond, _mutex, &absTime) ;
    if (status != 0 && WorkAroundNPTLTimedWaitHang) {
      pthread_cond_destroy (_cond) ;
      pthread_cond_init    (_cond, NULL);
    }
  }
  assert_status(status == 0 || status == EINTR ||
                status == ETIME || status == ETIMEDOUT,
                status, "cond_timedwait");

#ifdef ASSERT
  pthread_sigmask(SIG_SETMASK, &oldsigs, NULL);
#endif

  _counter = 0 ;
  status = pthread_mutex_unlock(_mutex) ;
  assert_status(status == 0, status, "invariant") ;
  // If externally suspended while waiting, re-suspend
  if (jt->handle_special_suspend_equivalent_condition()) {
    jt->java_suspend_self();
  }

  OrderAccess::fence();
}

 

 

 

UNSAFE_ENTRY定义:

#define UNSAFE_ENTRY(result_type, header) \
  JVM_ENTRY(result_type, header)

 

 

UNSAFE_END定义:

 

#define UNSAFE_END JVM_END
  

 

  

 

JVM_ENTRY定义:

#define JVM_ENTRY(result_type, header)                               \
extern "C" {                                                         \
  result_type JNICALL header {                                       \
    JavaThread* thread=JavaThread::thread_from_jni_environment(env); \
    ThreadInVMfromNative __tiv(thread);                              \
    debug_only(VMNativeEntryWrapper __vew;)                          \
    VM_ENTRY_BASE(result_type, header, thread)

 

 

#define VM_ENTRY_BASE(result_type, header, thread)                   \
  TRACE_CALL(result_type, header)                                    \
  HandleMarkCleaner __hm(thread);                                    \
  Thread* THREAD = thread;                                           \
  /* begin of body */

 

JVM_END定义:

#define JVM_END } }

 

所以,UNSAFE_ENTRY(void, Unsafe_Park(JNIEnv *env, jobject unsafe, jboolean isAbsolute, jlong time))展开后的代码:

extern "C" {                                                           
  void JNICALL Unsafe_Park(JNIEnv *env, jobject unsafe, jboolean isAbsolute, jlong time)) {                                         
    JavaThread* thread=JavaThread::thread_from_jni_environment(env); 
    ThreadInVMfromNative __tiv(thread);                              
    debug_only(VMNativeEntryWrapper __vew;)                          
    VM_ENTRY_BASE(result_type, header, thread)  

 

 

UnsafeWrapper定义:

#define UnsafeWrapper(arg) /*nothing, for the present*/

 

 

 

park/unpark操作

 

这两个操作通常配合在一起使用,park操作用于阻塞当前线程,unpark用于使阻塞在park操作代码处的线程退出阻塞。

 

 

unpark操作

该方法是一个native方法:

public native void unpark(Object thread);

该方法实现unsafe.cpp\hotspot\src\share\vm\prims目录下。

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

以上代码需要展开来才能看得懂,展开后代码如下:

如果定义了USDT2

extern "C" {

  void JNICALL Unsafe_Unpark(JNIEnv *env, jobject unsafe, jobject jthread) {

    JavaThread* thread=JavaThread::thread_from_jni_environment(env);

    ThreadInVMfromNative __tiv(thread);

 

    /* do nothing */

 

    HandleMarkCleaner __hm(thread);

    Thread* THREAD = thread;

 

    /* begin of body */

 

    /*nothing, for the present*/;

 

    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) {

      ;

      p->unpark();

    }

  }

}

 

如果没有定义USDT2

这里不展开USDT2宏没有定义的那段代码

 

其中主要的代码在:

p->unpark();

 

这块代码实现在os_solaris.cpp,在\hotspot\src\os\solaris\vm目录下。

void Parker::unpark() {

  int s, status ;

  status = os::Solaris::mutex_lock (_mutex) ;

  assert (status == 0, "invariant") ;

  s = _counter;

  _counter = 1;

  status = os::Solaris::mutex_unlock (_mutex) ;

  assert (status == 0, "invariant") ;

 

  if (s < 1) {

    status = os::Solaris::cond_signal (_cond) ;

    assert (status == 0, "invariant") ;

  }

}

 

 

 

分享到:
评论

相关推荐

    Java Unsafe类1

    这些操作在Java并发库的`LockSupport`类中被封装,`LockSupport.park()`和`LockSupport.unpark(Thread)`都是基于`Unsafe`实现的。这种机制在实现自定义同步原语时非常有用。 4. CAS(Compare and Swap)操作: CAS...

    Java Unsafe类实现原理及测试代码

    Java中的`Unsafe`类是一个非常底层的工具类,它提供了对内存操作的直接访问,类似于C语言中的指针。由于其强大的能力,`Unsafe`类能够执行一些常规Java API无法完成的任务,但也正因为这种能力,它也可能带来安全...

    简单谈一谈Java中的Unsafe类

    Java中的`Unsafe`类是一个非常特殊且强大的工具,它允许开发者绕过Java的常规安全机制,直接进行底层的内存操作和线程控制。虽然官方不推荐在常规开发中使用,但`Unsafe`类在某些高性能和低延迟的应用场景中扮演着...

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

    LockSupport是Java并发库中的一个核心工具类,它提供了线程的阻塞和唤醒功能,而Unsafe则是Java中的一个内部类,提供了对内存操作的直接访问。 LockSupport主要由一系列以`park`开头的方法和`unpark(Thread)`方法...

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

    LockSupport的park方法在内部是通过unsafe(sun.misc.Unsafe)类的park方法实现的。这个方法是本地的,意味着它直接在底层操作系统级别进行线程的阻塞和解除阻塞操作,因此效率较高。 LockSupport允许先unpark再...

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

    2. 创建自定义锁:通过Unsafe的CAS操作和park/unpark实现非阻塞锁或者其他同步机制。 3. 实现条件变量:如AbstractQueuedSynchronizer(AQS)的内部就是基于LockSupport和Unsafe构建的。 总结,理解Unsafe类和...

    Java中LockSupport的使用.docx

    Java的锁和同步器框架AbstractQueuedSynchronizer(AQS)就是通过LockSupport的`park()`和`unpark()`方法来管理线程的阻塞和恢复执行。 `park()`方法用于阻塞当前线程,如果当前线程能够获取到许可(即没有其他线程...

    java同步之如何写一个锁Lock

    Unsafe 类是一个底层的类,提供了许多底层操作,例如 CAS 操作、park 和 unpark 操作等。在这里,我们使用 Unsafe 类来实现 CAS 操作和 park 操作。 总结 通过手动实现一个锁,我们了解了锁的实现原理,包括对象头...

    基于JDK源码解析Java领域中的并发锁之设计与实现.pdf

    LockSupport是线程阻塞和唤醒的低级工具,提供了park()和unpark()方法,用于线程的挂起和恢复。它是基于 Unsafe 类实现的,可以实现非阻塞的线程挂起,提高并发效率。 三、Condition接口的设计与实现 Condition接口...

Global site tag (gtag.js) - Google Analytics