Cooperation between threads-waiting for wake-up mechanism

Waiting/notification mechanism

The wait-to-wake mechanism is a collaboration mechanism between multiple threads. When it comes to threads, we often think of competition between threads, such as each thread competing for locks, but multiple threads will also have a cooperative mechanism, just like you in a company Competitive relationship with your colleagues, but you will also cooperate to complete a project

Waiting for the wake-up mechanism is that after a thread performs a prescribed operation, another thread enters the waiting state (wait()), waits for the thread that has just performed the prescribed operation to execute their specified code, and then wakes the thread in the waiting state (Notify()); When there are multiple threads waiting, we can use notifyAll() to wake up all waiting threads if necessary.

wait/notify is a cooperation mechanism between threads

Method of waiting for notification mechanism

notify():

Notify a thread waiting on the object to wake it up from the wait method. The prerequisite for waking up is that the thread acquires the lock of the object. Threads that have not been acquired are still in the WAITING state.

notifyAll():

Notify all threads waiting on the object.

wait():

The thread that calls this method enters the WAITING state, and will only be awakened when it waits for another thread's notification or is interrupted. It should be noted that after calling the wait() method, the lock of the object will be released.

Wait timeout mode

The waiting timeout mode is to add timeout control to the waiting/notification mechanism and retain the notification mechanism. Even if the method execution time is too long, it will not permanently block the caller, but will return on time according to the caller's requirements. If other threads wake up the waiting thread in advance, the waiting can be ended early.

We found that waiting for timeout is not just a collaboration between threads, but can now be called thread-to-thread and time collaboration.

Ways to wait for timeout mode

Although the wait timeout mode is awakened by time control, the time is added to the parameter. Our notify series of methods can also take effect on threads waiting for overtime.

wait(long)

After the parameter long (milliseconds) is exceeded, if it is not awakened by other places, it will automatically wake up.

wait(long,int)

For more fine-grained control of the timeout period, nanoseconds can be achieved.

Wait/notify mode paradigm

Wait to follow the following principles

1. Acquire the lock of the object.

2. If the condition is not met, call the wait() method of the object, and check the condition after being notified.

3. If the condition is not met, the corresponding logic will be executed.

Picture 1.png

The notice follows the following principles

1. Acquire the lock

2. Change the condition so that the wait in the while() in the wait method can pass the next condition judgment after being awakened

3. Wake up all waiting threads to compete for locks. The threads that successfully compete for the lock determine whether they meet the conditions, continue to execute if they meet the conditions, and continue to wait for those that do not meet the conditions.

Picture 2.png

Before calling the wait and notify series of methods, the thread must obtain the object-level lock of the object, that is, the wait and notify methods can only be called in the synchronization method or synchronization block.

Waiting for the execution flow of the wake-up mechanism

  1. After the wait method is executed, the current thread is blocked here and the lock is released. At this time, other threads competing for locks will compete again (the threads waiting or waking up next time are completely random).
  2. After executing the notify series of methods, one or more threads in wait will be awakened at this time and rejoin the ranks of competing locks. When the competition succeeds, it will continue to execute from the position where the wait was blocked.
  3. The thread that executes the notify series of methods will release the lock after the synchronized code block is executed , and compete for the lock again.

The difference and usage scenarios of notify and notifyAll

Notify can not determine which thread was awakened. So it can be used in one-to-one waiting for wake-up. But when there are more than two wait methods using this lock, notifyAll should be used.

Wait for timeout mode to implement a connection pool

Requirements and design ideas

When calling a method, wait for a period of time (generally a given period of time). If the method can get the result within a given period of time, the result will be returned immediately. Otherwise, the default result will be returned after timeout.

Assuming that the waiting period is T, it can be inferred that it will time out after the current time is now+T.

The waiting duration is T for the first time, followed by (starting now+T)-current now

The timeout period is Future=now+T

Program implementation steps

First, we simulate the threads in the connection pool here as a List collection, so we set the member variable pool, and the length of the List represents the length of the connection pool.

image.png

Next, we set up a constructor to initialize the initial size of the thread pool (actually, set the length of the List).

image.png

We know that the threads in the thread pool have the concept of acquisition and return. When the calling layer acquires a thread in the thread pool, it means that there will be one less thread in our thread pool. When all the threads in the thread pool are dispatched, when the calling layer continues to obtain the threads in the thread pool, it needs to wait for the tasks of other threads in the thread pool to be executed and returned to succeed.

Then there are two options for obtaining threads in the thread pool at this time:

  1. Wait until the other tasks that hold the thread pool thread are executed and returned, and then successfully acquire the thread.
  2. Set a waiting time, if the thread cannot be successfully obtained within the time, null is returned to the calling layer (acquisition failure).

Let's take a look at the specific implementation plan:

image.png

So what is the logic of returning the connection?

image.png

In this way, we have realized a thread pool based on the waiting wake-up mechanism. Of course, this thread pool is not good. The biggest disadvantage is that there are too many round-robin judgments, which can easily cause a high CPU usage.

In practice, the bottom layer of our thread pool is implemented using a blocking queue.

What are the effects of yield(), sleep(), wait(), notify() and other methods on locks?

 

After calling yield.sleep, the lock held by the current thread lock will not be released.

After calling the wait method, the lock held by the current thread will be released and blocked at the wait method. And after being awakened, it will compete for the lock again. When the thread competes for the lock again, it continues to execute the code behind the blocked position of the wait method.

After calling the notify series method, it has no effect on the lock. The thread will release the lock naturally only after the synchronized synchronization code is executed.

Guess you like

Origin blog.csdn.net/weixin_47184173/article/details/115227085