理解 java.lang. Thread. 状态: 等待(停车)

首先,一个非常愚蠢的问题,我只是想知道“停车”是什么意思?线程是在等待被停放,还是刚刚被停放,因此处于等待状态?当停车发生时,需要占用多少 CPU/内存资源?放线的目的是什么?

其次,通过在 Java 线程 API中查看 park 方法

除非许可证可用,否则为线程调度目的禁用当前线程。

如果许可证是可用的,那么它将被使用,并且调用立即返回; 否则当前线程将因线程调度目的而被禁用,并处于休眠状态,直到发生以下三种情况之一... ..。

英语不是我的主要语言,所以我有一些困难理解,我的意思是“许可”作为一种“许可停放的线程”,所以问题如下:

  • 这是什么意思,什么是“许可证”,以及谁和如何检查这些许可证?
  • 这是什么意思: “如果许可证是可用的,那么它是消费的”,是否得到“停放”?
  • 如果第二点是正确的,那么“停车”和“休眠”的区别是什么?如果我有许可证,我可以永远停车,如果没有,我可以让它’休眠’?

谢谢

91125 次浏览

From the class description (at the top of the LockSupport javadoc) where it describes the permit:

This class associates with each thread that uses it, a permit (in the sense of the Semaphore class). A call to park will return immediately if the permit is available, consuming [the permit] in the process; otherwise [the call to park] may block. A call to unpark makes the permit available, if it was not already available. (Unlike with Semaphores though, permits do not accumulate. There is at most one.)

(I expanded the [text] to make it easier to read for non-English speakers.)

Hopefully somebody with a deeper understanding can elaborate on this. See axtavt's answer.

As a final note, a final quote from the javadoc:

These methods are designed to be used as tools for creating higher-level synchronization utilities, and are not in themselves useful for most concurrency control applications.

As i understand it, the "permit" is just an object that represent if a Thread can be "unparked" or not. And this is checked by the Thread itself (or de JRE when you try to park a Thread) The "is consumed" thing, i understand that the permit dissapears and the Thread is not dissabled.

I think you should learn a little bit more about multithreading.. Think of it as a dispenser with Objects called "permit". You tell to a Thread to park, and the Thread check the dispenser, if there is a "permit", the Thread take it and leaves(without park). If there is no "permit" in the dispenser the Thread is parked until a "permit" is avaliable (and you can put a "permit" in the dispenser with unpark.

As for the CPU/memory usage, i think that depends of the OS, etc...

Permit means a permission to continue execution. Parking means suspending execution until permit is available.

Unlike Semaphore's permits, permits of LockSupport are associated with threads (i.e. permit is given to a particular thread) and doesn't accumulate (i.e. there can be only one permit per thread, when thread consumes the permit, it disappears).

You can give permit to a thread by calling unpark(). A thread can suspend its execution until permit is available (or thread is interrupted, or timeout expired, etc) by calling park(). When permit is available, the parked thread consumes it and exits a park() method.

As per the java Thread State Documentation, A thread can go to WAITING state for three reasons:

  1. Object.wait with no timeout
  2. Thread.join with no timeout
  3. LockSupport.park

When you call a park method on a Thread, it disables the thread for thread scheduling purposes unless the permit is available. You can call unpark method to make available the permit for the given thread, if it was not already available.

So, when your Thread is in WAITING mode by LockSupport.park, it will show you as WAITING (parking).

Please make note that, you can call park on current Thread only. This is very helpful mechanism to implement Producer-Consumer Design Pattern.

The part that made me revisit this question that I could not get around while reading the documentation, was:

If the permit is available then it is consumed and the call returns immediately...

So when the permit is "available", who and how makes it available, so that it could get consumed immediately? This was somehow trivial to find out:

public static void main(String[] args) {


Thread parkingThread = new Thread(() -> {
System.out.println("Will go to sleep...");
sleepTwoSeconds();
System.out.println("Parking...");
// this call will return immediately since we have called  LockSupport::unpark
// before this method is getting called, making the permit available
LockSupport.park();
System.out.println("After parking...");
});


parkingThread.start();


// hopefully this 1 second is enough for "parkingThread" to start
// _before_ we call un-park
sleepOneSecond();
System.out.println("Un-parking...");
// making the permit available while the thread is running and has not yet
// taken this permit, thus "LockSupport.park" will return immediately
LockSupport.unpark(parkingThread);


}


private static void sleepTwoSeconds() {
try {
Thread.sleep(1000 * 2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}


private static void sleepOneSecond() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}

The code speaks for itself, the thread is running but not yet called LockSupport.park, while some other thread calls LockSupport.unpark on it - thus making the permit available. After that we call LockSupport.park and that returns immediately since the permit is available.

Once you think about it, this is a bit dangerous, if you expose your threads to some code you do not control and that code calls LockSupport.unpark while you park after that - it might not work.