从Java到JVM到OS线程睡眠(2)

获取最大限制大小limit。
如果超过 limit 则通过减法将其转成多次递归调用 sleep 函数。
获取 OSThread 对象,然后通过 OSThreadWaitState 设置线程状态为等待,修改操作分别在构造函数和析构函数中实现。
根据是否支持中断做不同实现,不需要中断则直接调用 Sleep 系统函数来实现。
如果要支持中断则接着做下面处理。
ThreadBlockInVM 主要是检查当前线程用不用进入 safepoint,后面再详细看。
接着主要到 WaitForMultipleObjects 系统函数,该函数能等待指定对象指定的毫秒数。如果等待过程中对象没有接到任何信号,则超过指定毫秒数后返回 WAIT_TIMEOUT ,如果等待过程中对象收到信号,则提前解除等待,此时返回的值为 OS_INTRPT ,即表示被中断了。

int os::sleep(Thread* thread, jlong ms, bool interruptable) {
  jlong limit = (jlong) MAXDWORD;

while (ms > limit) {
    int res;
    if ((res = sleep(thread, limit, interruptable)) != OS_TIMEOUT) {
      return res;
    }
    ms -= limit;
  }

assert(thread == Thread::current(), "thread consistency check");
  OSThread* osthread = thread->osthread();
  OSThreadWaitState osts(osthread, false /* not Object.wait() */);
  int result;
  if (interruptable) {
    assert(thread->is_Java_thread(), "must be java thread");
    JavaThread *jt = (JavaThread *) thread;
    ThreadBlockInVM tbivm(jt);

jt->set_suspend_equivalent();
    HANDLE events[1];
    events[0] = osthread->interrupt_event();
    HighResolutionInterval *phri=NULL;
    if (!ForceTimeHighResolution) {
      phri = new HighResolutionInterval(ms);
    }
    if (WaitForMultipleObjects(1, events, FALSE, (DWORD)ms) == WAIT_TIMEOUT) {
      result = OS_TIMEOUT;
    } else {
      ResetEvent(osthread->interrupt_event());
      osthread->set_interrupted(false);
      result = OS_INTRPT;
    }
    delete phri;
    jt->check_and_wait_while_suspended();
  } else {
    assert(!thread->is_Java_thread(), "must not be java thread");
    Sleep((long) ms);
    result = OS_TIMEOUT;
  }
  return result;
}
ThreadBlockInVM

前面说到 ThreadBlockInVM 会检查当前线程用不用进入 safepoint,它主要的逻辑如下:

首先设置 Java 线程状态,将状态加一,由 _thread_in_vm = 6 变为 _thread_in_vm_trans = 7,从“运行vm本身代码”到“相应的过度状态”。
os::is_MP() 用于判断计算机系统是否为多核系统,多核情况下需要做内存屏障处理,这是为了让每个线程都能实时同步状态。
内存屏障有两种方式,一种是 rderAccess::fence() ,它的实现是直接通过CPU指令来实现,汇编指令为 asm volatile ("lock; addl $0,0(%%rsp)" : : : "cc", "memory"); ,这种方式代价比较大。而另外一种为 InterfaceSupport::serialize_memory ,由 JVM 模拟实现,效率高一点。
调用 SafepointSynchronize::block 尝试在该安全点进行阻塞。
设置 Java 线程状态为 _thread_blocked ,即阻塞。

static inline void transition_and_fence(JavaThread *thread, JavaThreadState from, JavaThreadState to) {
    assert(thread->thread_state() == from, "coming from wrong thread state");
    assert((from & 1) == 0 && (to & 1) == 0, "odd numbers are transitions states");
    thread->set_thread_state((JavaThreadState)(from + 1));

if (os::is_MP()) {
      if (UseMembar) {
        OrderAccess::fence();
      } else {
        // Must use this rather than serialization page in particular on Windows
        InterfaceSupport::serialize_memory(thread);
      }
    }

if (SafepointSynchronize::do_call_back()) {
      SafepointSynchronize::block(thread);
    }
    thread->set_thread_state(to);

CHECK_UNHANDLED_OOPS_ONLY(thread->clear_unhandled_oops();)
  }

Linux公社的RSS地址:https://www.linuxidc.com/rssFeed.aspx

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/9e50add00c1b91600e5f9e4dd5674dd1.html