我已经看到线程可以通过不同的方式进入阻塞状态。我很想知道线程处于阻塞状态后究竟会发生什么。它如何回到运行状态。如果它被 sleep(time) 阻塞,那么它会在 time 毫秒后移动到可运行队列。如果它在 I/O 操作上被阻塞,一旦完成,它就会进入可运行队列。它在等待对象锁时如何进入可运行队列。它如何知道它等待的对象上的锁现在可用。有人还可以解释 I/O 上的阻塞线程如何工作的内部结构吗?如果我对上述任何主题的理解不正确,请纠正我。
谢谢
我已经看到线程可以通过不同的方式进入阻塞状态。我很想知道线程处于阻塞状态后究竟会发生什么。它如何回到运行状态。如果它被 sleep(time) 阻塞,那么它会在 time 毫秒后移动到可运行队列。如果它在 I/O 操作上被阻塞,一旦完成,它就会进入可运行队列。它在等待对象锁时如何进入可运行队列。它如何知道它等待的对象上的锁现在可用。有人还可以解释 I/O 上的阻塞线程如何工作的内部结构吗?如果我对上述任何主题的理解不正确,请纠正我。
谢谢
它在等待对象锁时如何到达可运行队列?
如果线程由于试图进入synchronized
块而被阻塞,当另一个线程(持有锁)通过退出synchronized
同一对象的块来释放锁时,该线程会自动标记为可运行。
如果当前线程由于调用而被阻塞someObject.wait()
,则当另一个线程调用时该线程被“释放” someObject.notify()
。
在字节码级别,它看起来如下:
[load some object, obj, onto the operand stack]
monitorenter // grab the lock
// do stuff
[load obj onto the operand stack again]
monitorexit // release the lock
如果其他人已经持有的锁obj
,该线程将一直挂起,monitorenter
直到其他线程调用monitorexit
。
JLS 没有具体说明如何实施monitorenter
和monitorexit
应该实施的具体细节。也就是说,它依赖于 JVM/OS。
有关更多详细信息,请参阅JLS 等待集和通知。
在接近代码的级别上,它看起来像这样:
线程 1:
Object mutex = new Object();
....
synchronized(mutex) {
//lock to mutex is acquired.
mutex.wait(); //lock to mutex is released. Thread is waiting for somebody to call notify().
doSomething();
}
线程 2:
synchronized(Thread1.mutex) {
//acquires the lock on mutex.
//Can be done only after mutex.wait() is called from Thread1
// and the lock is released
Thread1.mutex.notify(); // notifies Thread1 that it can be resumed.
}
一般来说,你应该记住 Thread.sleep() 持有资源的锁,但是 Thread.wait() 释放锁并且可以被其他线程通知。
AFAIK JVM 使用本机线程。因此,管理线程调度和上下文切换的是操作系统而不是 JVM。
您可以查看实际的 JVM 源代码。它是开放的。