Thread.yield、Thread.sleep、Object.wait、 LockSupport.park 对比

简介: Thread.yield、Thread.sleep、Object.wait、 LockSupport.park 对比

Thread.yield、Thread.sleep、Object.wait、 LockSupport.park  对比



sleep、wait、park区别


  • Thread.sleep() 不会释放占有的锁,Object.wait() 会释放会占有的锁
  • Thread.sleep() 必须传入时间,Object.wait() 可以传可不传,不传会一直阻塞下去。
  • Thread.sleep() 会自动唤醒,然后继续执行。
  • Object.wait() 不带时间方法,需要 Object.notify() 唤醒
  • Object.wait() 带时间,如果没有notify ,到时间会自动唤醒。
  • LockSupport.park 不需要捕获中断。
  • LockSupport.park() 方法可以被 LockSupport.unpark() 唤醒
  • Thread.sleep() 方法声明上抛出了 InterruptedException 异常
  • Thread.park() 不带超时,需要另一个线程执行 unpark 唤醒。
  • Thread.yield() 让出 CPU,不会释放锁,进入就绪状态。


640.png


小结

  • yield 相当于进行一次主动调度,当前线程放弃 CPU 使用权,重新进入 CPU 的运行队列,等待下一次调度。
  • sleep wait park 都是借助 pthread_cond_timedwait 实现阻塞,wait 还需要结合 ObjectMonitor 使用

Thread.yield

JNI  方法

public static native void yield();

JNI 入口

JVM_ENTRY(void, JVM_Yield(JNIEnv *env, jclass threadClass))
  // ...
  if (os::dont_yield()) return;
  // ...
  if (ConvertYieldToSleep) {
    os::sleep(thread, MinSleepInterval, false); // 使用sleep替代
  } else {
    os::yield(); // 默认调用os的yield实现
  }
JVM_END

最终会调用sched_yield()

void os::yield() {
  sched_yield();
}

复制代码这是一个linux的系统调用,下面是相关的内核代码

SYSCALL_DEFINE0(sched_yield)
{
  do_sched_yield();
  return 0;
}
static void do_sched_yield(void)
{
  // ...
  current->sched_class->yield_task(rq);
  // ...
  schedule();
}

这里就比较清晰了,首先调用当前任务(线程)对应调度类的yield_task()函数,然后调用schedule()函数执行一次重新调度,相当于为当前CPU选择下一个要执行的任务。对于普通线程来说,对应的调度队列是cfs_rq,对应的调度类是cfs_sched_class,对应的yield_task()函数是yield_task_fair()


Thread.sleep


是一个 Java  本地方法


public static native void sleep(long millis) throws InterruptedException;

sleep 入口,如果参数是 0 的话会转换成yield。


JVM_ENTRY(void, JVM_Sleep(JNIEnv* env, jclass threadClass, jlong millis))
  // ...
  if (millis == 0) {
    if (ConvertSleepToYield) { // 默认是false
      os::yield();
    } else {
      ThreadState old_state = thread->osthread()->get_state();
      thread->osthread()->set_state(SLEEPING);
      os::sleep(thread, MinSleepInterval, false); // 小睡一下
      thread->osthread()->set_state(old_state);
    }
  } else {
    ThreadState old_state = thread->osthread()->get_state();
    thread->osthread()->set_state(SLEEPING);
    if (os::sleep(thread, millis, true) == OS_INTRPT) {
      // 处理中断
    }
    thread->osthread()->set_state(old_state);
  }
  // ...
JVM_END

调用 os::sleep (jvm 函数,不是操作系统的)


int os::sleep(Thread* thread, jlong millis, bool interruptible) {
  ParkEvent * const slp = thread->_SleepEvent ;
  if (interruptible) {
    jlong prevtime = javaTimeNanos();
    for (;;) {
      if (os::is_interrupted(thread, true)) {
        return OS_INTRPT;
      }
      jlong newtime = javaTimeNanos();
      if (newtime - prevtime < 0) {
        // ...
      } else {
        millis -= (newtime - prevtime) / NANOSECS_PER_MILLISEC;
      }
      if(millis <= 0) {
        return OS_OK;
      }
      // ...
      {
        // ...
        slp->park(millis);  // 调用的是os::PlatformEvent::park
        // ...
      }
    }
  } else {
    // ...
  }
}

最终调用 ParkEvent 的 park 函数,实现如下:


int os::PlatformEvent::park(jlong millis) {
  int v ;
  for (;;) {
      v = _Event ;
      if (Atomic::cmpxchg (v-1, &_Event, v) == v) break ; // cas设置_Event
  }
  if (v != 0) return OS_OK ;  // os::PlatformEvent::unpark的时候会设置_Event=1,这里就会提前跳出
  struct timespec abst;
  compute_abstime(&abst, millis);  // 0. 计算绝对时间
  int ret = OS_TIMEOUT;
  int status = pthread_mutex_lock(_mutex);  // 1. 加mutex锁
  // ...
  ++_nParked ;
  while (_Event < 0) {
    status = os::Linux::safe_cond_timedwait(_cond, _mutex, &abst); // 2. 等待
    if (status != 0 && WorkAroundNPTLTimedWaitHang) {
      pthread_cond_destroy (_cond);
      pthread_cond_init (_cond, os::Linux::condAttr()) ;
    }
    if (!FilterSpuriousWakeups) break ;                 // previous semantics
    if (status == ETIME || status == ETIMEDOUT) break ;
  }
  --_nParked ;
  if (_Event >= 0) {
     ret = OS_OK;
  }
  _Event = 0 ;
  status = pthread_mutex_unlock(_mutex); // 3. 释放mutex锁
  // ...
  return ret;
}

Object.wait


wait 也是 JNI 方法


public final native void wait(long timeout) throws InterruptedException;

wait 一般是需要配合 synchrononized 使用的.入口是 JVM_MonitorWait


JVM_ENTRY(void, JVM_MonitorWait(JNIEnv* env, jobject handle, jlong ms))
  JVMWrapper("JVM_MonitorWait");
  Handle obj(THREAD, JNIHandles::resolve_non_null(handle));
  JavaThreadInObjectWaitState jtiows(thread, ms != 0);
  if (JvmtiExport::should_post_monitor_wait()) {
    JvmtiExport::post_monitor_wait((JavaThread *)THREAD, (oop)obj(), ms);
  }
  ObjectSynchronizer::wait(obj, ms, CHECK);
JVM_END

wait 代码实现如下:


void ObjectSynchronizer::wait(Handle obj, jlong millis, TRAPS) {
  if (UseBiasedLocking) {
    BiasedLocking::revoke_and_rebias(obj, false, THREAD);
    assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
  }
  if (millis < 0) {
    TEVENT (wait - throw IAX) ;
    THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "timeout value is negative");
  }
  ObjectMonitor* monitor = ObjectSynchronizer::inflate(THREAD, obj()); // 膨胀为重量级锁
  DTRACE_MONITOR_WAIT_PROBE(monitor, obj(), THREAD, millis);
  monitor->wait(millis, true, THREAD); // 调用wait
  dtrace_waited_probe(monitor, obj, THREAD);
}

ObjectMonitor的wait函数 实现


void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) {
  Thread * const Self = THREAD ;
  // ...
  if (interruptible && Thread::is_interrupted(Self, true) && !HAS_PENDING_EXCEPTION) {
     // ...
     THROW(vmSymbols::java_lang_InterruptedException()); // 处理中断
     return ;
   }
  // ...
  AddWaiter (&node) ; // 1. 添加到ObjectMonitor的等待队列_WaitSet中
  // ...
  exit (true, Self) ; // 2. 释放java的monitor锁(也就是monitorexit)
  // ...
       if (interruptible &&
           (Thread::is_interrupted(THREAD, false) ||
            HAS_PENDING_EXCEPTION)) {
           // Intentionally empty
       } else if (node._notified == 0) {
         if (millis <= 0) {
            Self->_ParkEvent->park () ;
         } else {
            ret = Self->_ParkEvent->park (millis) ; // 3. 等待,和Thread::sleep一样的
         }
       }
  //...
}

LockSupport.park


park 也是 JNI  方法


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

Unsafe  实现


UNSAFE_ENTRY(void, Unsafe_Park(JNIEnv *env, jobject unsafe, jboolean isAbsolute, jlong time))
  // ...
  thread->parker()->park(isAbsolute != 0, time);
  // ...
UNSAFE_END

park  方法实现, 调用的是 Parker 的park 函数,不是os:PlatformEvent::park


void Parker::park(bool isAbsolute, jlong time) {
  if (Thread::is_interrupted(thread, false)) {
    return;
  }
  timespec absTime;
  if (time < 0 || (isAbsolute && time == 0) ) { // don't wait at all
    return;
  }
  if (time > 0) {
    unpackTime(&absTime, isAbsolute, time); // 0. 计算绝对时间
  }
  if (Thread::is_interrupted(thread, false) ||
      pthread_mutex_trylock(_mutex) != 0) { // 1. 尝试加mutex锁
    return;
  }
  int status ;
  if (_counter > 0)  { // no wait needed
    _counter = 0;
    status = pthread_mutex_unlock(_mutex); // 2.1 在park之前调用了unpark,就不会wait了
    // ...
    return;
  }
  if (time == 0) {
    _cur_index = REL_INDEX; // arbitrary choice when not timed
    status = pthread_cond_wait (&_cond[_cur_index], _mutex) ;  // 2.2 入参为0,一直等待
  } else {
    _cur_index = isAbsolute ? ABS_INDEX : REL_INDEX;
    // 2.3 带超时的等待
    status = os::Linux::safe_cond_timedwait (&_cond[_cur_index], _mutex, &absTime) ;
    if (status != 0 && WorkAroundNPTLTimedWaitHang) {
      pthread_cond_destroy (&_cond[_cur_index]) ;
      pthread_cond_init    (&_cond[_cur_index], isAbsolute ? NULL : os::Linux::condAttr());
    }
  }
  _counter = 0 ;
  status = pthread_mutex_unlock(_mutex) ; // 3. 释放mutex锁
}


可以看到 park 最终是依赖 pthread_cond_timedwait 方法实现阻塞。

LockSupport.park() 的实现原理是通过二元信号量做阻塞,unpark() 方法会释放一个许可证,park()方法则是获取许可证,要注意的是,无论执行多少次 unpark()方法,也最多只会有一个许可

相关文章
|
2月前
|
传感器 人工智能 算法
分层架构解耦——如何构建不依赖硬件的具身智能系统
硬件与软件的彻底解耦,并通过模块化、分层的架构进行重构,是突破这一瓶颈、构建通用型具身智能系统的核心基石。这种架构将具身智能系统解耦为三个核心层级:HAL、感知决策层和任务执行层。这一模式使得企业能够利用预置的技能库和低代码工具快速配置新任务,在不更换昂贵硬件的前提下,实现从清洁机器人到物流机器人的快速功能切换。本文将通过对HAL技术原理、VLA大模型和行为树等核心技术的深度剖析,并结合Google RT-X、RobotecAI RAI和NVIDIA Isaac Sim等主流框架的案例,论证这一新范式的可行性与巨大潜力,探讨硬件解耦如何将机器人从一个“工具”升级为“软件定义”的“多面手”,从而
440 3
|
5月前
|
机器学习/深度学习 传感器 人工智能
模型微调
本文深入探讨了从GPT3到ChatGPT及DeepSeek等大模型中微调技术的关键作用。微调(Fine-tuning)是在预训练模型基础上,通过特定任务数据调整参数以优化性能的技术。文中对比了全参数微调与参数高效微调(如LoRA、Adapter),并介绍了模型蒸馏和强化学习在AI优化中的角色。通过实例解析,如“厨师学川菜”,生动说明了微调的原理与优势。此外,还提供了云平台(如百炼、Hugging Face Space)上的微调实践指南,帮助开发者快速上手。未来,随着算力提升和新技术发展,微调将更高效、广泛应用于各类场景。
|
NoSQL 前端开发 rax
Dev 日志 | 一次 Segmentation Fault 和 GCC Illegal Instruction 编译问题排查
本文记录了 Segmentation fault (core dumped) 和 internal compiler error: Illegal instruction 两个错误信息的 Debug 过程
2895 0
Dev 日志 | 一次 Segmentation Fault 和 GCC Illegal Instruction 编译问题排查
|
存储 安全 算法
AES算法
【10月更文挑战第30天】AES算法
1415 2
|
网络协议 Java
DatagramSocket和Socket的区别及使用场景
DatagramSocket和Socket这两个类。它们分别基于UDP和TCP协议,提供了不同的特性和适用场景
422 1
|
设计模式 缓存 JavaScript
什么是代理对象
【9月更文挑战第3天】什么是代理对象
498 0
|
存储 JSON 安全
网络原理 - HTTP / HTTPS(2)——http请求
网络原理 - HTTP / HTTPS(2)——http请求
424 2
open-feign自定义反序列化decoder
open-feign自定义反序列化decoder
469 0
|
XML 存储 JSON
HTTP 协议详解
什么是协议?就是一种规定,描述了通信双方要按照什么样的格式传输信息。而本文讲解的HTTP 也是协议中的一种。
HTTP 协议详解