Document directory
- [Concurrent threads]
- [Java thread object]
- [Start () of a thread instance can only generate one thread]
Multi-threaded programming-basics (1)
[Preface]
With the development of computer technology, programming models become more and more complex and diversified. However, the multi-threaded programming model is the final model of the current computer system architecture. With the increasing CPU clock speed, the X86 architecture hardware has become a bottle, in which the CPU clock speed is up to 4 GB. In fact, the CPU at the G clock speed is close to the peak.
If you cannot fundamentally update the current CPU architecture (which is unlikely to take a long time), you can continue to improve the CPU performance by using the hyper-threading CPU mode. To maximize the performance of the CPU, the job system and applications must be changed to parallel processing systems and concurrent applications based on multi-threaded programming models.
Therefore, mastering multi-threaded programming models is not only a means to improve application performance, but also a core idea of the next generation programming model. The purpose of multi-threaded programming is to "maximize the use of CPU resources". when processing a thread does not need to occupy the CPU but only deals with resources such as I/O and oembios, this gives other threads that need to occupy CPU resources the opportunity to obtain CPU resources. Basically, this is the ultimate goal of multi-threaded programming.
[First problem to be clarified]
Like the difference between a program and a process, to master multi-threaded programming, the first problem to be clarified is:Difference between a thread object and a thread.
A thread object is an object that can generate a thread. For example, the thread object and the runnable object in the Java platform. A thread is a guiding sequence that is being executed. On the Java platform, it refers to the relatively independent process in the run method body starting from the start () of a thread object.
Given the author's level, it is impossible to describe their definitions with more accurate words. However, the two concepts with essential differences should be carefully understood by beginners. As the introduction goes deeper and routine analysis increases, they will gradually understand the true meanings they represent.
Difficulties in the world must begin with ease, and great events in the world must begin with details.
Let's start with the simplest "single thread": (1) single thread with quotation marks (2) Based on Java.
class BeginClass{ public static void main(String[] args){ for(int i=0;i<100;i++) System.out.println("Hello,World!"); } }
If we have compiled the Java file successfully and then typed in the command line:
Java beginclass
What happened now? Every Java programmer will be exposed to this question in the first minute of learning Java.
But do you know what it actually happens?
The JVM process is started. In the same JVM process, one and only one process is itself. Then, in this JVM environment, all programs run with threads. JVM will first generate a main thread to run the entry point of the specified program. In this program, the main thread starts to run from the main method. After the main method is completed, the main thread runs completely. The JVM process also exits.
What we can see is that a main thread is running the main method, so there is only one thread to execute the program logic.
It isSingle thread. This is the single-threaded environment provided by JVM. In fact, there are at least background threads such as garbage collection and other non-Java threads at the JVM bottom layer, but these threads are not accessible to us, we only think it is single-threaded.
The main thread is started by JVM itself, which is not generated from the thread object here. In this thread, it runs the command sequence of the main method. Understand it, but it does not have much to study.
[Multithreading]
class MyThread extends Thread{ public void run(){ System.out.println("Thread say:Hello,World!"); } } public class MoreThreads{ public static void main(String[] args){ new MyThread(); new MyThread().start(); System.out.println("Main say:Hello,World"); } }
When this program is executed, the first line of the main method generates a thread object, but no thread is started.
The second line of the main method generates a thread object and starts a thread.
The third line of the main method. After a thread is generated and started, the main thread continues to execute other statements.
We will not study the specific content of the thread object. Let's look back at the two concepts above,Thread objectAndThread. In Java, the thread object is a common object subclass generated by JVM. The thread is a running process in which the CPU is allocated to this object. What we are talking about is what the thread is doing, not what a thread object is doing, but what the running process is doing. If you cannot understand them for a while, don't worry, but remember that they are not the same thing.
Tired? Why?
Introduction of multithreading based on this style is not liked and accepted by everyone. If you do not like it, it will not waste your time. If you accept it, let's take a look at the next section.
Multi-threaded programming-basics (II)
Before entering the thread object on the Java platform, I will first insert two basic concepts based on some issues in the basic article (1.
[Concurrent threads]
In a single CPU system, the System Scheduling can run only one thread at a certain time. Although this debugging mechanism has multiple forms (most of which are dominated by time slice patrol), in any case, the method of running the thread to be continuously switched is calledConcurrent). In a multi-CPU system, more than two threads can run at the same time.Parallel (parallel).
In all the discussions above, please forgive me. I cannot use the most accurate words to define terms such as concurrency and parallelism, however, in my experience, I can tell you how it is. If you see that some of the "standard" documents I mentioned are different, as long as they mean the same, then you should not pick a thorn.
[Java thread object]
Now let's start to examine the thread objects in Java.
In Java, there are two ways to start a thread. First, call the START () method of the thread instance directly, and second
Pass the runable instance to a thread instance and call its start () method.
As mentioned above, the thread object and thread are two completely different concepts. Here, let's go further to generate a thread instance, which does not mean that the thread is started. The starting thread means that the corresponding thread of the instance is started on a thread object and will not disappear immediately after the thread ends.
I don't need to talk much about the basic knowledge I can see from many books. Since it is basic knowledge, I also focus on what I cannot read from common documents. So in this section, I will focus on the difference between the two thread objects in the thread generation mode.
class MyThread extends Thread{ public int x = 0; public void run(){ for(int i=0;i<100;i++){ try{ Thread.sleep(10); }catch(Exception e){} System.out.println(x++); } }}
If we generate an instance of mythread and call its start () method, the thread corresponding to this instance will be generated:
public class Test { public static void main(String[] args) throws Exception{ MyThread mt = new MyThread(); mt.start(); }}
Needless to say, 0 to 99 will be printed in the end. Now we have a little bit of fun:
public class Test { public static void main(String[] args) throws Exception{ MyThread mt = new MyThread(); mt.start(); System.out.println(101); }}
Needless to say, in the basic article (1), we know that because of a single CPU, 101 is usually printed first, and then 0 to 99 is printed. However, we can control the thread to run it as we mean:
public class Test { public static void main(String[] args) throws Exception{ MyThread mt = new MyThread(); mt.start(); mt.join(); System.out.println(101); }}
Well, we finally see the thread corresponding to the MT instance (if I say that the MT Thread Sometimes, please do not blame me, but I try not to say so ). After running, the main thread prints 101. Because we let the current thread (here is the main thread) wait until the running of the MT thread ends. "Calling the join () method on thread object A is to let the currently executing thread wait until the thread corresponding to thread object a finishes running. "Please be sure to deeply understand and memorize this sentence, and the purpose of bringing this knowledge point here is to let you continue to look at the following example:
public class Test { public static void main(String[] args) throws Exception{ MyThread mt = new MyThread(); mt.start(); mt.join(); Thread.sleep(3000); mt.start(); }}
After the thread object Mt runs, let's take a break from the main thread, and then start the thread on the thread object again. The result is as follows:
Exception in thread "Main" Java. Lang. illegalthreadstateexception
That is, after a thread object is run once at a time, it can no longer run the second time. Let's take a look at its specific implementation:
public synchronized void start() { if (started) throw new IllegalThreadStateException(); started = true; group.add(this); start0(); }
Once the START () method is called for an instance of a thread, the started flag of this instance is marked as true. In fact, no matter whether the thread is executed or not, you only need to call start () once () there is no longer a chance to run, which means:
[Start () of a thread instance can only generate one thread]
So what should we do if we want to generate multiple threads (also known as thread pools) on an instance? This is the great function that the runnable interface brings to us.
class R implements Runnable{ private int x = 0; public void run(){ for(int i=0;i<100;i++){ try{ Thread.sleep(10); }catch(Exception e){} System.out.println(x++); } }}
Like its name, the runnable instance can run, but it cannot run directly. It needs to be packaged by the thread object to run:
public class Test { public static void main(String[] args) throws Exception{ new Thread(new R()).start(); }}
Of course, this result is no different from Mt. Start. However, if we wrap a runnable instance to the thread object multiple times, we can see that they actually start the thread on the same instance:
public class Test { public static void main(String[] args) throws Exception{ R r = new R(); for(int i=0;i<10;i++) new Thread(r).start(); }}
X is an instance object, but X is added to 999, which means that the 10 threads run on the same r object. Please note that this example runs on a single CPU, so the synchronization of objects operated by multiple threads is not performed simultaneously. Synchronization is simplified for convenience. in the real environment, you cannot predict the environment in which the program will run. Therefore, you must consider synchronization.
Here we will provide a complete example to illustrate the differences between different thread generation methods:
Package debug; import Java. io. *; import Java. lang. thread; Class mythread extends thread {public int x = 0; Public void run () {system. out. println (++ X) ;}} class R implements runnable {private int x = 0; Public void run () {system. out. println (++ X) ;}} public class test {public static void main (string [] ARGs) throws exception {for (INT I = 0; I <10; I ++) {thread t = new mythread (); T. start ();} thread. sleep (10000); // run the preceding thread r = new R (); For (INT I = 0; I <10; I ++) {thread t = new thread (r); T. start ();}}}
The 10 threads generated by the above 10 thread objects are printed once every 10 times. The 10 threads generated by the following 10 thread objects are printed from 1 to 10 during runtime. We call the following 10 threadsMultiple threads of the same instance (runnable instance).
In the next section, we will study the thread object method. I will not introduce much content that can be read in general documents.
For more information, see.
Multi-threaded programming-basics (III)
Several important methods of thread objects
Although the common methods of thread objects can be learned through the API documentation, there are many methods that are not detailed only from the API description.
I was going to use a section to finish some important knowledge about the thread method, but it is estimated that it would take a very long time to complete this process, it may take several sections to finish some important knowledge related to the thread method.
First, we will explain the START () method in the basic article (2.
After a thread object is generated, if you want to generate an execution thread, you must call its start () method. you have to describe the run method when introducing this method. in fact, the run method of the thread object is completely an interface callback method, which is the specific logic to be completed by the thread object. simply put, you do what you want to do in the run, and you do not need to control when you do it. You only need to call the START () method, JVM manages this thread object to generate a thread and register it in the thread processing system.
On the surface, the START () method calls the run () method. In fact, the START () method does not directly call the run method. before jdk1.5, the START () method was a local method, and how it finally called the run method was not familiar to Java programmers. in jdk1.5, the original local start () method is replaced by start0 (), and the other pure Java start () calls the local method start0 (), the START () method verifies a global variable (object variable) started. If it is true, the START () throws an exception, the local method start0 () is not called. Otherwise, set the variable to true and call start0 ().
We can see that the START () method can only be run once to control a thread object. this is because the running of a thread needs to obtain the current environment, including the security, permissions of the parent thread, priority, and other conditions. If a thread object can be run multiple times, A static thread is defined to obtain the corresponding permissions and priorities in one environment. After the execution is complete, it uses the original permissions, priorities, and other attributes to run in the current environment, this results in unpredictable results. to put it simply, it is necessary to manage threads to allow a thread object to run only once successfully.
The most essential function of the START () method is to apply for another thread space from the CPU to execute the code in the run () method. It is two lines from the current thread, run in a relatively independent thread space. That is to say, if you directly call the run () method of the thread object, it will also be executed, but it is executed in the current thread, run () after the method is executed, continue to execute the following code. after the start () method is called, the code of the run () method is executed concurrently with the current thread (single CPU) or concurrently (multiple CPUs.
Therefore, remember one sentence [calling the run method of the thread object will not generate a new thread]. Although the same execution result can be achieved, the execution process and execution efficiency are different.
[Thread's interrupt () method, interrupted () and isinterrupted ()]
These three methods are closely related and complex. Although their respective functions are very clear, most people do not really understand the relationship between them.
The interrupt () method is an instance method, and it is also the most strange method. In Java, the thread was initially designed as something "obscure, until now, its semantics is not as accurate as its name. Most people think that if a thread calls the interrupt () method, the corresponding thread should be interrupted and an exception will be thrown. In fact, when a thread object calls the interrupt () method, the thread corresponding to it is not interrupted, but its interruption status is changed.
Change the status of the current thread to the interrupted state. If there is no other impact, the thread will continue to execute it on its own.
The thread throws an exception only when the thread executes methods such as sleep, wait, and join, or throws an exception by checking the interrupt status.
If the corresponding thread of the thread object is immediately interrupted after interrupt () is called, the interrupted () method cannot be executed.
Because the interrupted () method is a static method, that is, it can only be called on the current thread. If a thread interrupt () has been interrupted, then how does it make itself interrupted ()?
Because a thread only changes the interrupt status after calling interrupt (), it can continue to run until sleep, wait, join, or other methods are called or an exception is thrown by itself, it can call interrupted () to clear the interrupt status (will still be the same) the interrupted () method will check the interrupt status of the current thread, if the value is "interrupted", the current thread is changed to "non-interrupted" and true is returned. If the value is "non-interrupted", false is returned, it not only checks whether the current thread is interrupted, but also ensures that the current thread is not interrupted, so it is called "interrupted ", the isinterrupted () method only checks whether the thread corresponding to the thread object is in the interrupted state and does not change its state.
At present, you can only remember the functions of these three methods. Only by going deep into multi-threaded programming practices can you see why they are object methods and class methods.
When the thread is interrupted and an interruptedexception exception is thrown. We will discuss it in detail in the article on improvement.
[Sleep (), join (), yield () method]
In the current section, I can only explain the functions and calling principles of these methods. As for why, I cannot go into depth in the basic article. I can only explain in detail in the article on how to improve it.
The sleep () method is a class method, that is, for the current thread, the programmer cannot specify a thread to sleep, but only when the current thread executes the sleep () method, specifies the time for sleep (for other threads to run ). in fact, it can only be a class method and called on the current thread. imagine how to sleep () if you call the sleep () method of a thread object, if the thread corresponding to this object is not running, how does it sleep ()? So only the current thread, because it is being executed, can you ensure that it can call the sleep () method.
Principle: [do not call the thread's sleep () method in the synchronous method], or simply put, you should not call the sleep () method for general level programmers.
The join () method, as stated in section 1, calling the join method on a thread object is the current thread waiting for the end of the thread object. For example, there are two jobs, work a takes 10 seconds, and work B takes 10 seconds or more. We first generate a thread in the program to do work B, and then do work.
New? B (). Start (); // do work B
A (); // do work
After job A is completed, I will wait for the result of Job B to handle it. If Job B is not completed, I will not be able to perform the following job C, so
B? B? =? New? B ();
B. Start (); // do B
A (); // do work
B. Join (); // wait for Job B to finish.
C (); // continue working C.
Principle: [join is the only correct way to test other working states]. I have seen many people, even some doctoral students. If another job is not completed while dealing with a job, let's let the current working thread sleep (x). I asked him, how do you specify this X? How do you know it is 100 ms instead of 99 Ms or 101 Ms? In fact, this is the essence of the onxxx event. We don't have to wait for a long time to do anything, but do it when the waiting work is just done.
The yield () method is also a class method. It is called only on the current thread for the same reason. The main reason is to let the current thread discard the time slice principle assigned this time: [not very necessary, there is no reason to call it]. calling this method does not increase any efficiency, but reduces the total cycle of the CPU. The preceding thread methods can only be briefly mentioned based on (BASICS. in the future, I will discuss in detail with examples.
For other methods of the thread, see the API documentation. The next section describes non-thread methods, but the two [three] object methods closely related to the thread:
[Wait (), notify ()/notifyall ()]
This is a very important method in multithreading.
Several important methods of thread objects
Although the common methods of thread objects can be learned through the API documentation, there are many methods that are not detailed only from the API description.
I was going to use a section to finish some important knowledge about the thread method, but it is estimated that it would take a very long time to complete this process, it may take several sections to finish some important knowledge related to the thread method.
First, we will explain the START () method in the basic article (2.
After a thread object is generated, if you want to generate an execution thread, you must call its start () method. you have to describe the run method when introducing this method. in fact, the run method of the thread object is completely an interface callback method, which is the specific logic to be completed by the thread object. simply put, you do what you want to do in the run, and you do not need to control when you do it. You only need to call the START () method, JVM manages this thread object to generate a thread and register it in the thread processing system.
On the surface, the START () method calls the run () method. In fact, the START () method does not directly call the run method. before jdk1.5, the START () method was a local method, and how it finally called the run method was not familiar to Java programmers. in jdk1.5, the original local start () method is replaced by start0 (), and the other pure Java start () calls the local method start0 (), the START () method verifies a global variable (object variable) started. If it is true, the START () throws an exception, the local method start0 () is not called. Otherwise, set the variable to true and call start0 ().
We can see that the START () method can only be run once to control a thread object. this is because the running of a thread needs to obtain the current environment, including the security, permissions of the parent thread, priority, and other conditions. If a thread object can be run multiple times, A static thread is defined to obtain the corresponding permissions and priorities in one environment. After the execution is complete, it uses the original permissions, priorities, and other attributes to run in the current environment, this results in unpredictable results. to put it simply, it is necessary to manage threads to allow a thread object to run only once successfully.
The most essential function of the START () method is to apply for another thread space from the CPU to execute the code in the run () method. It is two lines from the current thread, run in a relatively independent thread space. That is to say, if you directly call the run () method of the thread object, it will also be executed, but it is executed in the current thread, run () after the method is executed, continue to execute the following code. after the start () method is called, the code of the run () method is executed concurrently with the current thread (single CPU) or concurrently (multiple CPUs.
Therefore, remember one sentence [calling the run method of the thread object will not generate a new thread]. Although the same execution result can be achieved, the execution process and execution efficiency are different.
[Thread's interrupt () method, interrupted () and isinterrupted ()]
These three methods are closely related and complex. Although their respective functions are very clear, most people do not really understand the relationship between them.
The interrupt () method is an instance method, and it is also the most strange method. In Java, the thread was initially designed as something "obscure, until now, its semantics is not as accurate as its name. Most people think that if a thread calls the interrupt () method, the corresponding thread should be interrupted and an exception will be thrown. In fact, when a thread object calls the interrupt () method, the thread corresponding to it is not interrupted, but its interruption status is changed.
Change the status of the current thread to the interrupted state. If there is no other impact, the thread will continue to execute it on its own.
The thread throws an exception only when the thread executes methods such as sleep, wait, and join, or throws an exception by checking the interrupt status.
If the corresponding thread of the thread object is immediately interrupted after interrupt () is called, the interrupted () method cannot be executed.
Because the interrupted () method is a static method, that is, it can only be called on the current thread. If a thread interrupt () has been interrupted, then how does it make itself interrupted ()?
Because a thread only changes the interrupt status after calling interrupt (), it can continue to run until sleep, wait, join, or other methods are called or an exception is thrown by itself, it can call interrupted () to clear the interrupt status (will still be the same) the interrupted () method will check the interrupt status of the current thread, if the value is "interrupted", the current thread is changed to "non-interrupted" and true is returned. If the value is "non-interrupted", false is returned, it not only checks whether the current thread is interrupted, but also ensures that the current thread is not interrupted, so it is called "interrupted ", the isinterrupted () method only checks whether the thread corresponding to the thread object is in the interrupted state and does not change its state.
At present, you can only remember the functions of these three methods. Only by going deep into multi-threaded programming practices can you see why they are object methods and class methods.
When the thread is interrupted and an interruptedexception exception is thrown. We will discuss it in detail in the article on improvement.
[Sleep (), join (), yield () method]
In the current section, I can only explain the functions and calling principles of these methods. As for why, I cannot go into depth in the basic article. I can only explain in detail in the article on how to improve it.
The sleep () method is a class method, that is, for the current thread, the programmer cannot specify a thread to sleep, but only when the current thread executes the sleep () method, specifies the time for sleep (for other threads to run ). in fact, it can only be a class method and called on the current thread. imagine how to sleep () if you call the sleep () method of a thread object, if the thread corresponding to this object is not running, how does it sleep ()? So only the current thread, because it is being executed, can you ensure that it can call the sleep () method.
Principle: [do not call the thread's sleep () method in the synchronous method], or simply put, you should not call the sleep () method for general level programmers.
The join () method, as stated in section 1, calling the join method on a thread object is the current thread waiting for the end of the thread object. For example, there are two jobs, work a takes 10 seconds, and work B takes 10 seconds or more. We first generate a thread in the program to do work B, and then do work.
New? B (). Start (); // do work B
A (); // do work
After job A is completed, I will wait for the result of Job B to handle it. If Job B is not completed, I will not be able to perform the following job C, so
B? B? =? New? B ();
B. Start (); // do B
A (); // do work
B. Join (); // wait for Job B to finish.
C (); // continue working C.
Principle: [join is the only correct way to test other working states]. I have seen many people, even some doctoral students. If another job is not completed while dealing with a job, let's let the current working thread sleep (x). I asked him, how do you specify this X? How do you know it is 100 ms instead of 99 Ms or 101 Ms? In fact, this is the essence of the onxxx event. We don't have to wait for a long time to do anything, but do it when the waiting work is just done.
The yield () method is also a class method. It is called only on the current thread for the same reason. The main reason is to let the current thread discard the time slice principle assigned this time: [not very necessary, there is no reason to call it]. calling this method does not increase any efficiency, but reduces the total cycle of the CPU. The preceding thread methods can only be briefly mentioned based on (BASICS. in the future, I will discuss in detail with examples.
For other methods of the thread, see the API documentation. The next section describes non-thread methods, but the two [three] object methods closely related to the thread:
[Wait (), notify ()/notifyall ()]
This is a very important method in multithreading.
[Wait (), notify ()/notityall () method]
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. |
|
Class = "Left" 2. Thread a accepts the user's ticket booking request and prepares to issue the 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 synchornized keyword is used to implement mutex control (jdk1.5 has developed a new mechanism for the moment)
[Synchornized keyword]
Declare a unit as synchornized so that only one thread can operate on this method at a time.
Some people say that synchornized 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 synchornized keyword locked? Who got the lock?
For synchronization blocks, synchornized obtains the object lock in the parameter:
synchornized(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(); synchornized(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(){ synchornized(o){ //............... } }}
All threads that execute synchornized (o) to the test instance can obtain the monitoring lock only by one thread.
Sometimes we will:
public void test(){ synchornized(this){ //............... } }
Only one thread can execute all the threads that execute the test instance. the synchornized (o) and synchornized (this) have different scopes, because when the thread that runs to the test instance synchornized (o) waits, other threads can execute the synchornized (O1) part of the test instance, but multiple threads have only one synchornized (this).]
For
synchornized(Test.class){ //............... }
For such synchronization blocks, only one thread can be executed by all threads that call multiple test instances.
[Synchornized method]
If a method is declared as synchornized, it is equivalent to calling synchornized (this) on the method ).
If a static method is declared as synchornized, it is equivalent to calling synchornized (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 {public synchornized void test () {// obtain the condition. Int X must be greater than 100. If (x <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 synchornized 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 multi-thread programming.Practice
Multi-thread programming BASICS (4)