Definition of BLOCKED state
As mentioned before, the simple definition of BLOCKED is:
A thread that is blocked waiting for a monitor lock is in this state. (A thread that is blocked waiting for a monitor lock is in this state.)
For a more detailed definition, please refer to the javadoc in Thread.State:
/** * Thread state for a thread blocked waiting for a monitor lock. * A thread in the blocked state is waiting for a monitor lock * to enter a synchronized block/method or * reenter a synchronized block/method after calling * {@link Object#wait() Object.wait}. */ BLOCKED,
This sentence is very long and can be broken into two simple sentences to understand .
A thread in the blocked state is waiting for a monitor lock to enter a synchronized block/method.
A thread in blocked state is waiting for a monitor lock to enter a synchronized block or method.
A thread in the blocked state is waiting for a monitor lock to reenter a synchronized block/method after calling Object.wait.
A thread in the blocked state is waiting for a monitor lock after it calls the Object.wait method to re-enter a synchronized block or method.
Blocked when entering (enter) synchronization block
Let me talk about the first sentence first, this is easier to understand.
Monitor lock is used for synchronous access to achieve mutual exclusion between multiple threads. So once a thread acquires the lock and enters the synchronized block, before it comes out, if other threads want to enter, they will be blocked outside the synchronized block because they cannot obtain the lock. At this time, the state is BLOCKED.
Note: The entry and exit of this state are not under our control. When the lock is available, the thread will recover from the blocking state.
We can use some code to demonstrate this process:
@Test public void testBlocked() throws Exception { class Counter { int counter; public synchronized void increase() { counter++; try { Thread.sleep(30000); } catch (InterruptedException e) { throw new RuntimeException(e); } } } Counter c = new Counter(); Thread t1 = new Thread(new Runnable() { public void run() { c.increase(); } }, "t1线程"); t1.start(); Thread t2 = new Thread(new Runnable() { public void run() { c.increase(); } }, "t2线程"); t2.start(); Thread.sleep(100); // 确保 t2 run已经得到执行 assertThat(t2.getState()).isEqualTo(Thread.State.BLOCKED); }
The above defines an access counter counter with a synchronous increase method. The t1 thread enters first and then sleeps in the synchronization block, causing the lock to be delayed. When t2 tries to execute the synchronization method, it is blocked because it cannot obtain the lock.
VisualVM monitoring shows the status of the t2 thread:
The "monitor" status on the picture is the BLOCKED status. You can see that t2 is in the BLOCKED state during t1 sleep.
BLOCKED state can be regarded as a special kind of WAITING, specifically waiting for a lock.
wait blocks when reentering the synchronized block
Now look at the second sentence again:
2. A thread in the blocked state is waiting for a monitor lock to reenter a synchronized block/method after calling Object. wait.
A thread in the blocked state is waiting for a monitor lock after it calls the Object.wait method to re-enter a synchronized block or method.
This sentence is a bit convoluted, and it is not easy to translate into a concise Chinese sentence. It is not easy to understand this sentence without a good understanding of the relevant background of wait. Let’s expand on it a little bit here. Since it is reenter, it means there are two enters. The process is like this:
Call the wait method must be in a synchronized block, that is, you must first acquire the lock and enter the synchronized block. This is the first enter.
After calling wait, the lock will be released and entered into the waiting queue (wait set) of this lock.
After receiving the notify or notifyAll notification from other threads, the waiting thread cannot resume execution immediately because the stop is in the synchronized block and the lock has been released, so it must reacquire the lock before reentering (reenter) Synchronize the block and resume execution from the last wait point. This is the second time to enter, so it is called reenter.
But the lock will not be given to it first. The thread still has to compete with other threads for the lock. This process is actually the same as the enter process, so it may also cause BLOCKED because the lock has been occupied by other threads.
This process is called reenter a synchronized block/method after calling Object.wait.
We also use a piece of code to demonstrate this process:
@Test public void testReenterBlocked() throws Exception { class Account { int amount = 100; // 账户初始100元 public synchronized void deposit(int cash) { // 存钱 amount += cash; notify(); try { Thread.sleep(30000); // 通知后却暂时不退出 } catch (InterruptedException e) { throw new RuntimeException(e); } } public synchronized void withdraw(int cash) { // 取钱 while (cash > amount) { try { wait(); } catch (InterruptedException e) { throw new RuntimeException(e); } } amount -= cash; } } Account account = new Account(); Thread withdrawThread = new Thread(new Runnable() { public void run() { account.withdraw(200); } }, "取钱线程"); withdrawThread.start(); Thread.sleep(100); // 确保取钱线程已经得到执行 assertThat(withdrawThread.getState()).isEqualTo(Thread.State.WAITING); Thread depositThread = new Thread(new Runnable() { public void run() { account.deposit(100); } }, "存钱线程"); Thread.sleep(10000); // 让取钱线程等待一段时间 depositThread.start(); Thread.sleep(300); // 确保取钱线程已经被存钱线程所通知到 assertThat(withdrawThread.getState()).isEqualTo(Thread.State.BLOCKED); }
Brief introduction to the above code scenario:
There is an account object with deposit and withdraw methods, and the initial amount is 100 yuan.
The money withdrawal thread starts first and enters the (enter) synchronization block. It tries to withdraw 200 yuan. When it is found that the money is not enough, wait is called, the lock is released, and the thread hangs (WAITING state).
The deposit thread starts after 10 seconds, deposits money and notifies the withdrawal thread, but then continues to sleep in the synchronization block, resulting in the lock not being released.
After receiving the notification, the money-withdrawing thread exits the WAITING state, but no longer holds the lock. When trying to re-enter the synchronization block to resume execution, the lock has not been released by the money-saving thread, so it is blocked (BLOCKED state) ).
Monitored display:
As shown in the figure, the money withdrawal thread is WAITING first, and is blocked (BLOCKED) after receiving the notification because it cannot obtain the lock.
Summary
Looking at these two sentences together, they have two meanings, but they still mean the same thing. Simply put, it is enter, reenter, or enter. In summary:
When synchronization cannot be entered because the lock cannot be obtained block, the thread is in the BLOCKED state.
If a thread is in the BLOCKED state for a long time, consider whether a deadlock has occurred.
BLOCKED state can be regarded as a special kind of waiting, which is a subdivision of the traditional waiting state:
Since the WAITING state has not been mentioned yet, and the wait method is involved here, the wait is also slightly discussed above. After doing some analysis, in the next chapter, the two states WAITING and TIMED_WAITING will be analyzed in more detail.