网站首页 > 精选教程 正文
Java 中有时需要将线程进入睡眠状态,这时一般我们就会通过 Thread.sleep 使线程进入睡眠状态,接下去就看看执行该语句在 JVM 中做了什么。
简单例子
以下是一个简单的例子,使主线程睡眠5秒钟。
public class TestSleep { public static void main(String[] args) { try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } } }
JVM 中的线程
在继续往 JVM 层看 start0 本地方法前,我们先了解下 JVM 中的相关线程,这将有助于后面更好理解 Java 层线程与 JVM 中的线程对应关系。
在 JVM 中,也用 C++ 定义了一些 Thread 类,它们的继承结构如下,其中对于 Java 层线程到 JVM 层主要相关的有 Java 层的 java.lang.Thread、JavaThread 和 OSThread。
java.lang.Thread 属于 Java 层的线程对象,每个 Java 层对象都会在 JVM 中使用 oop 来表示,所以它也会在 JVM 中产生一个 oop。
Thread 是 C++ 定义的线程基类,除了 OSThread 类,作为其他线程的基类,它包含了 OSThread 对象的指针。
JavaThread 是 C++ 定义的线程类,我们在 Java 层创建的线程对象会使用 JavaThread 对象来表示,它包含了指向线程的 oop 的指针。
OSThread 是 C++ 定义的线程,它不与其他线程构成继承关系,它是 JVM 对不同操作系统的线程的统一抽象,它维护了操作系统线程的句柄,用于获取操作系统的线程。
--Thread --JavaThread --CodeCacheSweeperThread --CompilerThread --JvmtiAgentThread --ServiceThread --NamedThread --ConcurrentGCThread --VMThread --WorkerThread --AbstractGangWorker --GCTaskThread --WatcherThread --OSThread
sleep方法
在 Thread 类中, sleep 是一个静态且本地方法。
public static native void sleep(long millis) throws InterruptedException;
Thread.c
Java 层声明的本地方法对应实现在 Thread.c 中, sleep 是一个注册到 JVM 中的方法,它与 JVM 中的 JVM_Sleep 函数绑定了,所以实现逻辑在 JVM_Sleep 函数里。逻辑为:
JVMWrapper("JVM_Sleep") 用于调试。
睡眠时间不能为负。
是否已经被中断了。
JavaThreadSleepState jtss(thread) 用于修改线程状态并做一些统计,当睡眠结束后,会修改回线程状态,在 JavaThreadSleepState 的析构函数中修改。
睡眠时间如果为0,则根据 ConvertSleepToYield 做不同处理,它表示是否将 sleep 操作转为 yield 操作。分别调用 os::naked_yield 和 os::sleep 处理,封装了不同操作系统的调用实现,后面以 Windows 为例分别看相应实现。
通过 thread->osthread()->get_state() 获取 OSThread 对象,并将其状态设置为 SLEEPING等到 sleep 结束后设置回原来的状态。
如果睡眠时间大于0,则做类似操作,不过它支持中断。
发送事件,结束。
os::naked_yield
naked_yield 函数的实现很简单,就直接调用 SwitchToThread 系统函数。通过该函数可以让系统查看是否有其他线程迫切需要CPU,将CPU让给其他线程,如果没有其他线程则立即返回。
void os::naked_yield() { SwitchToThread(); } JVM_ENTRY(void, JVM_Sleep(JNIEnv* env, jclass threadClass, jlong millis)) JVMWrapper("JVM_Sleep"); if (millis 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) { if (!HAS_PENDING_EXCEPTION) { if (event.should_commit()) { event.set_time(millis); event.commit(); } HOTSPOT_THREAD_SLEEP_END(1); THROW_MSG(vmSymbols::java_lang_InterruptedException(), "sleep interrupted"); } } thread->osthread()->set_state(old_state); } if (event.should_commit()) { event.set_time(millis); event.commit(); } HOTSPOT_THREAD_SLEEP_END(0); JVM_END os::sleep
获取最大限制大小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指令来实现,汇编指令为 asmvolatile ("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();) }
猜你喜欢
- 2024-10-29 Java线程:它们的内存效率高吗? java线程内存溢出
- 2024-10-29 一文搞懂Java多线程 java多线程使用方法
- 2024-10-29 JAVA反射机制详解,一学就会 java反射机制实现原理
- 2024-10-29 Java中的锁详解 java中锁的概念
- 2024-10-29 2022新出java100+经典面试题,赶紧保存
- 2024-10-29 「超级详细」Java线程实现原理 java线程实现的三种方式
- 2024-10-29 AI预测手机睡眠模式 手机监测睡眠质量
- 2024-10-29 一文详解 Java 的几把 JVM 级锁 java中的各种锁详细介绍
- 2024-10-29 “全栈2019”Java多线程第十五章:后台线程中的finally
- 2024-10-29 详细介绍一下Java中的wait()方法与sleep()方法的区别与联系?
你 发表评论:
欢迎- 04-11Java面试“字符串三兄弟”String、StringBuilder、StringBuffer
- 04-11Java中你知道几种从字符串中找指定的字符的数量
- 04-11探秘Java面试中问的最多的String、StringBuffer、StringBuilder
- 04-11Python字符串详解与示例(python字符串的常见操作)
- 04-11java正则-取出指定字符串之间的内容
- 04-11String s1 = new String("abc");这句话创建了几个字符串对象?
- 04-11java判断字符串中是否包含某个字符
- 04-11关于java开发中正确的发牌逻辑编写规范
- 最近发表
-
- Java面试“字符串三兄弟”String、StringBuilder、StringBuffer
- Java中你知道几种从字符串中找指定的字符的数量
- 探秘Java面试中问的最多的String、StringBuffer、StringBuilder
- Python字符串详解与示例(python字符串的常见操作)
- java正则-取出指定字符串之间的内容
- String s1 = new String("abc");这句话创建了几个字符串对象?
- java判断字符串中是否包含某个字符
- 关于java开发中正确的发牌逻辑编写规范
- windows、linux如何后台运行jar(并且显示进程名)
- 腾讯大佬私人收藏,GitHub上最受欢迎的100个JAVA库,值得学习
- 标签列表
-
- nginx反向代理 (57)
- nginx日志 (56)
- nginx限制ip访问 (62)
- mac安装nginx (55)
- java和mysql (59)
- java中final (62)
- win10安装java (72)
- java启动参数 (64)
- java链表反转 (64)
- 字符串反转java (72)
- java逻辑运算符 (59)
- java 请求url (65)
- java信号量 (57)
- java定义枚举 (59)
- java字符串压缩 (56)
- java中的反射 (59)
- java 三维数组 (55)
- java插入排序 (68)
- java线程的状态 (62)
- java异步调用 (55)
- java中的异常处理 (62)
- java锁机制 (54)
- java静态内部类 (55)
- java怎么添加图片 (60)
- java 权限框架 (55)
本文暂时没有评论,来添加一个吧(●'◡'●)