Java multi-thread programming-basics (part 4)
[Wait (), notify ()/notityall () method]Source: go deep into Java column Reprinted from dev2dev's axman.
There are a lot of things to explain about these two methods. in the following illustration, there may be a lot of points that you cannot understand at once, but after reading this section, Even if you cannot fully understand it, you must go back and remember the following two sentences:
[Wait (), notify ()/notityall () is a common object method (implemented in the object superclass), rather than a thread object method]
[Wait (), notify ()/notityall () methods can only be called in synchronous methods]
[Thread mutex control]
When multiple threads operate on an object at the same time, operations by one thread on this object may change its state, and this state will affect the real results of another thread on this object.
In this example, we can see in too many documents that the two ticket dealers sell the same ticket at the same time.
Thread |
Thread B |
. 1 thread a queries the deposit ticket in the database and finds that the ticket C can be sold. |
|
2. Thread a accepts the user's ticket booking request and prepares to issue a ticket |
|
|
3. Switch to thread B for execution. |
|
4. Thread B queries the deposit ticket in the database and finds that the ticket C can be sold. |
|
5. Thread B sold the ticket |
6. Switch to thread a for execution. Thread a sells a sold ticket. |
|
Therefore, a mechanism is required to manage the occurrence of such problems. When a thread is executing an inseparable part, other threads cannot execute this part at the same time.
For example, a mechanism that allows only one thread to execute a certain execution unit at a certain time is called mutex control or shared mutex (mutual exclusion)
In Java, the synchronized keyword is used to implement mutex control (jdk1.5 has developed a new mechanism for the moment)
[Synchronized keyword]
Declare a unit as synchronized so that only one thread can operate on this method at a time.
Some people say that synchronized is a lock. In fact, it does have a lock, but it is a very complicated problem.
Each object has only one monitor lock, which can be obtained by only one thread at a time. after a thread acquires the lock, other threads can only wait for the thread to release the lock before obtaining it.
So what is the synchronized keyword locked? Who got the lock?
For synchronization blocks, synchronized obtains the object lock in the parameter:
- Synchronized (OBJ ){
- //...............
- }
When the thread executes this operation, it first needs to obtain the lock of the OBJ instance. If the thread is not obtained, it can only wait. if multiple threads are executed here, only one thread can obtain the OBJ lock and execute the statements in {}. Therefore, the control program varies depending on the scope of the OBJ object.
Suppose:
- Public void test (){
- Object o = new object ();
- Synchronized (OBJ ){
- //...............
- }
- }
This program cannot control anything. When the object o = new object () is executed between multiple threads, an object will be generated each time and a monitoring lock will be acquired for this object, so they will be executed happily.
If it is a class property:
- Class test {
- Object o = new object ();
- Public void test (){
- Synchronized (o ){
- //...............
- }
- }
- }
All threads that execute synchronized (o) to the test instance can obtain the monitoring lock only by one thread.
Sometimes we will:
- Public void test (){
- Synchronized (this ){
- //...............
- }
- }
Only one thread can execute all the threads that execute the test instance. synchronized (o) and synchronized (this) have different scopes, because when the thread that runs to the test instance synchronized (o) waits, other threads can execute the synchronized (O1) part of the test instance, but multiple threads have only one synchronized (this).]
For
- Synchronized (test. Class ){
- //...............
- }
For such synchronization blocks, only one thread can be executed by all threads that call multiple test instances.
[Synchronized Method]
If a method is declared as synchronized, it is equivalent to calling synchronized (this) on the method ).
If a static method is declared as synchronized, it is equivalent to calling synchronized (class. Class) on the method ).
Now go to the wait method and the notify/notifyall method. these two (or three) methods are the methods of the object, rather than the methods of the thread object. like locks, they are executed on an object called in a thread.
- Class test {
- Int X;
- Public synchronized void test () throws interruptedexception {
- // Obtain the condition. Int X must be greater than 100;
- If (X & lt; 100)
- Wait ();
- }
- }
Here, the method is not added to try {} catch () {}. If it is not clear on which object the wait () method is called, this. Wait ();
Suppose:
Test T = new test ();
Now, both threads run the T. Test (); method. Thread A obtains the t object lock and enters the test () method.
At this time, X is less than 100, so thread a enters the waiting state.
After a thread calls the wait method, the thread enters the waitset of the object, which is a virtual object, however, the JVM must have such a data structure to record which threads are waiting in the current object.
When a thread enters the waiting state, it releases the lock and allows other threads to obtain the lock.
Therefore, thread B has the opportunity to obtain the lock released by thread a and enter the test () method. If X is still less than 100, thread B also enters the T Lounge.
The two threads can only wait for other threads to call notity [all] to wake up.
However, if the wait (time) method with parameters is called, thread a and thread B will automatically wake up after waiting for the time in the lounge.
[Why do all real applications use the while clause instead of the IF clause?]
In actual programming, we can see that a lot of examples are used?
While (X & lt; 100)
Wait (); go (); instead of using if. Why?
If (x <100) is insecure when multiple threads are executed simultaneously. because if thread a and thread B both wait in the T lounge, then another thread causes x = 100 and calls the notifyall method, thread a continues to execute the following go (). after the execution is complete, X may be less than 100. For example, if -- X is called in the following program, switch to thread B, and thread B does not continue to judge. Go () is directly executed (); an error condition is generated. Only the while clause can ensure that thread B checks again.
[Policy/policyall method]
Both methods wake up the threads in the rest area of an object. y can only wake up one thread, but which one is uncertain, while notifyall wakes up all the threads in the lounge of this object.
Generally, we should use notifiall () In most cases, unless you explicitly know that only one thread is awakened.
So is the current thread entering the lounge of an object by calling the wait () method of an object? In fact, to call the wait () method of an object, only the current thread obtains the Lock of this object, in other words, it must be in the synchronization method of this object or the synchronization block with this object as the parameter.
- Class mythread extends thread {
- Test T = new test ();
- Public void run (){
- T. Test ();
- System. Out. println ("thread say: Hello, world! ");
- }
- }
- Public class test {
- Int x = 0;
- Public void test (){
- If (x = 0)
- Try {
- Wait ();
- } Catch (exception e ){
- }
- }
- Public static void main (string [] ARGs) throws exception {
- New mythread (). Start ();
- }
- }
This thread will not directly print thread say: Hello, world! Without entering t's wait method !.
If changed:
- Public class test {
- Int x = 0;
- Public synchronized void test (){
- If (x = 0)
- Try {
- Wait ();
- } Catch (exception e ){
- }
- }
- Public static void main (string [] ARGs) throws exception {
- New mythread (). Start ();
- }
- }
We can see that the thread has been waiting. Note that there is no other thread to wake up after this thread enters the waiting state. It will wait until it is forced out of the JVM environment.
So remember:
[If a thread wants to call the wait () method of an object, it must first obtain the monitoring lock of the object. Once wait () is called, the lock is released immediately.]
The above is a brief introduction to the basic thread knowledge. We cannot really understand the true meaning of the thread without entering the instance. In the next section, we will use the instance to enter the multi-thread programming practice.