HotSpot Park原理

上一篇了解了HotSpot关于CAS的支持,作为JUC并发支持,HotSpot提供了Park来支持线程的挂起,唤醒操作。在synchronized层面ObjectMonitor通过ParkEvent来操作线程挂起唤醒,在AQS层面UnSafe通过Parker来操作线程的挂起唤醒。

一.Parker

在JUC中我们考察AQS中的park,以ReentrantLock为例作为入口。

java/util/concurrent/locks/ReentrantLock.java

public class ReentrantLock implements Lock, java.io.Serializable {
    //加锁
	public void lock() {
        sync.acquire(1);
    }
    //解锁
     public void unlock() {
        sync.release(1);
    }
}

java/util/concurrent/locks/AbstractQueuedSynchronizer.java
AQS用于实现其他各种锁的核心,内部通过链表来管理同步线程,其中线程挂起唤醒借助了UnSafe类

public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer{
	//尝试获取锁,获取失败则,新增一个独占节点加入到等待队列
	public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }
    //遍历等待队列
 	final boolean acquireQueued(final Node node, int arg) {
        boolean interrupted = false;
        try {
            for (;;) {
                final Node p = node.predecessor();
                //循环队列直到链表头,表头结点获取锁成功,则将node插到表头
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    return interrupted;
                }
                //获取失败的节点挂起
                if (shouldParkAfterFailedAcquire(p, node))
                    interrupted |= parkAndCheckInterrupt();
            }
        } catch (Throwable t) {
            cancelAcquire(node);
            if (interrupted)
                selfInterrupt();
            throw t;
        }
    }
    
    //挂起
	private final boolean parkAndCheckInterrupt() {
        LockSupport.park(this);
        return Thread.interrupted();
    }
    
    public final boolean release(int arg) {
    //尝试释放锁
        if (tryRelease(arg)) {
            Node h = head;
            if (h != null && h.waitStatus != 0)
                unparkSuccessor(h);
            return true;
        }
        return false;
    }
    
    private void unparkSuccessor(Node node) {
     
        int ws = node.waitStatus;
        if (ws < 0)
            node.compareAndSetWaitStatus(ws, 0);
        //循环链表,找到该唤醒的节点,唤醒该节点对应的线程
        Node s = node.next;
        if (s == null || s.waitStatus > 0) {
            s = null;
            for (Node p = tail; p != node && p != null; p = p.prev)
                if (p.waitStatus <= 0)
                    s = p;
        }
        if (s != null)
          	//唤醒
            LockSupport.unpark(s.thread);
    }
}

java/util/concurrent/locks/LockSupport.java

public class LockSupport {

	//UnSafe类
    private static final Unsafe U = Unsafe.getUnsafe();
    //parkBlocker位于Thread.java
    private static final long PARKBLOCKER = U.objectFieldOffset
            (Thread.class, "parkBlocker");
    private static final long SECONDARY = U.objectFieldOffset
            (Thread.class, "threadLocalRandomSecondarySeed");
    private static final long TID = U.objectFieldOffset
            (Thread.class, "tid");

     //blocker为AbstractQueuedSynchronizer
	 public static void park(Object blocker) {
        Thread t = Thread.currentThread();
        setBlocker(t, blocker);
        U.park(false, 0L);
        setBlocker(t, null);
    }
    
    //设置阻塞对象arg即AbstractQueuedSynchronizer ,PARKBLOCKER 为Thread类中的parkBlocker成员
	private static void setBlocker(Thread t, Object arg) {
        // Even though volatile, hotspot doesn't need a write barrier here.
        U.putObject(t, PARKBLOCKER, arg);
    }
  
     public static void unpark(Thread thread) {
        if (thread != null)
            U.unpark(thread);
    }
}

java/lang/Thread.java

public class Thread implements Runnable {
	volatile Object parkBlocker;
}

jdk/internal/misc/Unsafe.java

public final class Unsafe {
	 @HotSpotIntrinsicCandidate
    public native void putObject(Object o, long offset, Object x);
    @HotSpotIntrinsicCandidate
    public native void park(boolean isAbsolute, long time);
     @HotSpotIntrinsicCandidate
    public native void unpark(Object thread);
}

src/share/vm/prims/unsafe.cpp

  1. obj : Thread
  2. offset: Thread类中的parkBlocker内存偏移
  3. x_h:AbstractQueuedSynchronizer
UNSAFE_ENTRY(void, Unsafe_PutObject(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jobject x_h)) {
  oop x = JNIHandles::resolve(x_h);  //查找解析AQS的HotSpot内部oop
  oop p = JNIHandles::resolve(obj);  //查找解析Thread的HotSpot内部oop
  //将Thread的parkBlocker设置为AQS
  if (UseCompressedOops) {
    oop_store((narrowOop*)index_oop_from_field_offset_long(p, offset), x);
  } else {
    oop_store((oop*)index_oop_from_field_offset_long(p, offset), x);
  }
} UNSAFE_END

src/share/vm/prims/unsafe.cpp

  1. isAbsolute: 是否一直挂起
  2. time:挂起时间
UNSAFE_ENTRY(void, Unsafe_Park(JNIEnv *env, jobject unsafe, jboolean isAbsolute, jlong time)) {
  EventThreadPark event;
  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());
  if (event.should_commit()) {
    oop obj = thread->current_park_blocker();
    event.set_parkedClass((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

src/share/vm/prims/unsafe.cpp
jthread为需要唤醒的线程

UNSAFE_ENTRY(void, Unsafe_Unpark(JNIEnv *env, jobject unsafe, jobject jthread)) {
  Parker* p = NULL;
  if (jthread != NULL) {
    //查找解析Thread的HotSpot内部oop
    oop java_thread = JNIHandles::resolve_non_null(jthread);
    if (java_thread != NULL) {
      jlong lp = java_lang_Thread::park_event(java_thread);
      if (lp != 0) {
        p = (Parker*)addr_from_java(lp);  //获取线程对应的Parker
      } 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) { //绑到线程上,下一次备用,显然这里是为了提高效率
              java_lang_Thread::set_park_event(java_thread, addr_to_java(p));
            }
          }
        }
      }
    }
  }

  if (p != NULL) {
    HOTSPOT_THREAD_UNPARK((uintptr_t) p);
    p->unpark(); //唤醒
  }
} UNSAFE_END

src/share/vm/runtime/thread.hpp

Parker*     parker() { return _parker; }

src/share/vm/runtime/park.hpp
Parker的声明

class Parker : public os::PlatformParker {
	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();
}

src/os/linux/vm/os_linux.cpp
Parker的挂起实现

void Parker::park(bool isAbsolute, jlong time) {
  //无锁下快速检查_counter
  if (Atomic::xchg(0, &_counter) > 0) return;

  Thread* thread = Thread::current();
  JavaThread *jt = (JavaThread *)thread;
  //挂起前检查是否被中断
  if (Thread::is_interrupted(thread, false)) {
    return;
  }
  ThreadBlockInVM tbivm(jt);

  //再次检查
  if (Thread::is_interrupted(thread, false) || pthread_mutex_trylock(_mutex) != 0) {
    return;
  }

  int status;
  if (_counter > 0)  { // 无需等待
    _counter = 0;
    status = pthread_mutex_unlock(_mutex);
     //lock指令同步内存数据,对所有线程立即可见
    OrderAccess::fence();
    return;
 }
  //设置为非Object.wait()
  OSThreadWaitState osts(thread->osthread(), false /* not Object.wait() */);
  jt->set_suspend_equivalent();
  //这里做Linux线程条件挂起
  if (time == 0) {
    _cur_index = REL_INDEX; 
    status = pthread_cond_wait(&_cond[_cur_index], _mutex);
  } else {
    _cur_index = isAbsolute ? ABS_INDEX : REL_INDEX;
    status = pthread_cond_timedwait(&_cond[_cur_index], _mutex, &absTime);
  }
  _cur_index = -1;

  
#ifdef ASSERT
  pthread_sigmask(SIG_SETMASK, &oldsigs, NULL);
#endif
  //线程被唤醒了
  _counter = 0;
  status = pthread_mutex_unlock(_mutex);
  //lock指令同步内存数据,对所有线程立即可见
  OrderAccess::fence();
  // 设置线程挂起状态
  if (jt->handle_special_suspend_equivalent_condition()) {
    jt->java_suspend_self();
  }
}

src/os/linux/vm/os_linux.cpp
Parker的唤醒实现

void Parker::unpark() {
  //获取线程锁状态
  int status = pthread_mutex_lock(_mutex);
  const int s = _counter;
  _counter = 1;
  // 线程解除锁定
  int index = _cur_index;
  status = pthread_mutex_unlock(_mutex);
  if (s < 1 && index != -1) {
    // 唤醒线程
    status = pthread_cond_signal(&_cond[index]);
  }
}

二.ParkEvent

ParkEvent和synchronized有关,在ObjectMonitor一篇中,线程进入同步块参与锁竞争,没竞争到锁时该线程会被挂起,这个挂起操作是由ParkEvent来实现的。
src/share/vm/runtime/objectMonitor.cpp

void ObjectMonitor::EnterI(TRAPS) {
	 ......
	 // park self
    if (_Responsible == Self || (SyncFlags & 1)) {
      TEVENT(Inflated enter - park TIMED);
      //挂起指定时间
      Self->_ParkEvent->park((jlong) recheckInterval);
      // Increase the recheckInterval, but clamp the value.
      recheckInterval *= 8;
      if (recheckInterval > MAX_RECHECK_INTERVAL) {
        recheckInterval = MAX_RECHECK_INTERVAL;
      }
    } else {
      TEVENT(Inflated enter - park UNTIMED);
      //挂起
      Self->_ParkEvent->park();
    }
    ......
}

上述Self即为当前线程,thread中定义了四种ParkEvent

  1. _ParkEvent 是给synchronized用的
  2. _SleepEvent是给线程sleep()用的
  3. _MutexEvent是给虚拟机内部MutexMonitor用的,这个监视器用于HotSpot内部用的,ObjectMonitor是给Java层用的
  4. _MuxEvent是个底层Mutex使用

src/share/vm/runtime/thread.hpp

public:
  volatile intptr_t _Stalled;
  volatile int _TypeTag;
  ParkEvent * _ParkEvent;                     // for synchronized()
  ParkEvent * _SleepEvent;                    // for Thread.sleep
  ParkEvent * _MutexEvent;                    // for native internal Mutex/Monitor
  ParkEvent * _MuxEvent;                      // for low-level muxAcquire-muxRelease

挂起操作_Event状态转变

  1. -1 => -1 : 违法状态
  2. 1 => 0 : 不挂起立即返回
  3. 0 => -1 : 阻塞挂起

src/os/linux/vm/os_linux.cpp

void os::PlatformEvent::park() {       // AKA "down()"
  int v;
  //CAS快速判断
  for (;;) {
    v = _Event;
    if (Atomic::cmpxchg(v-1, &_Event, v) == v) break;
  }
  if (v == 0) {
    // 加锁
    int status = pthread_mutex_lock(_mutex);
    ++_nParked;
    while (_Event < 0) {
      //阻塞挂起
      status = pthread_cond_wait(_cond, _mutex);
      if (status == ETIME) { status = EINTR; }
    }
    --_nParked;
    _Event = 0;
    status = pthread_mutex_unlock(_mutex);
    //lock指令同步内存数据,对所有线程立即可见
    OrderAccess::fence();
  }
}

src/os/linux/vm/os_linux.cpp

唤醒操作_Event状态转变

  1. 0 => 1 : 返回,不唤醒
  2. 1 => 1 : 返回,不唤醒
  3. -1 => 0 or 1 : 唤醒
void os::PlatformEvent::unpark() {
  //无锁快速判断
  if (Atomic::xchg(1, &_Event) >= 0) return;
  //获取锁定状态
  int status = pthread_mutex_lock(_mutex);
  int AnyWaiters = _nParked;
  status = pthread_mutex_unlock(_mutex);
  if (AnyWaiters != 0) {
    //信号唤醒
    status = pthread_cond_signal(_cond);
  }
}

HotSpot内部通过多种手段实现线程的同步和通讯。对于synchronized,HotSpot通过ObjectSynchronizer来实现偏向锁,轻量级锁,重量级锁的管理和Java线程的同步,通过ObjectMonitor和ParkEvent来实现线程的通讯。而对于AQS,HotSpot通过volatile,CAS提供内存模型一致性,通过Parker来协调线程的挂起唤醒。而对于其他诸如Thread.sleep()是通过ParkEvent来实现的。再如已经废弃的yield(),suspend(),resume(),HotSpot通过内部MutexMonitor(非ObjectMonitor)来实现,这里就不在展开了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值