Reprinted from: http://hi.baidu.com/person_space/blog/item/e39cc6c43adfbeaf8326ac43.html
Link: Another good explanation (http://hi.baidu.com/feiyuyitiao/blog/item/af89821e5df88b1941341750.html)
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).
Next, insert the topic:
A post on csdn: I am a beginner in struts. I can see in the book that when an action receives multiple requests at the same time, all requests share an action instance, that is to say, action processes multiple requests in multiple threads. However, I looked at the source code of the action class and found that it does not implement the runable interface or inherit the Thread class. actionservlet and requestprocessor do not inherit any classes or interfaces, so I don't quite understand how action processes multiple requests in multiple threads?
Reply: clarify the concept that the multi-thread request is managed by containers, that is, Tomcat/JBoss, etc. The multi-thread that you start is not managed by them. Therefore, action can be understood as servlet, and servlet does not need to be able to be multi-threaded by itself. The Container thread will automatically call it. The order is: Request-> container thread-> struts filter-> your action I think, action is managed by the filter of your struts, while your filter runs in the container thread, and the thread is opened by the container. Tomcat and JBoss both have thread pools, the process of starting a thread is about the same as writing a socket program by yourself. The container you select has multiple threads. You can regard action as a client terminal, the container is regarded as a server. Multiple routing tasks are only used by the server, and action is only sent for request.
The 10 threads generated by the above 10 thread objects are printed once every 10 times. Because every new thread generates a thread object, the member variable X of this thread is generated, and a thread corresponds to its own thread object. Five thread instances are generated, all have their own X. When JVC is assigned to a thread run, only the X value of the thread is changed.
The 10 threads generated by the following 10 thread objects are printed from 1 to 10 during runtime. Because 10 threads share one thread object. For example, actions in struts1 are singleton. One request starts one thread and multiple requests correspond to multiple threads in concurrent operations. These threads share one action instance. Therefore, if an instance variable appears in the action, the thread is not secure.
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.
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 thread-to-image run method is completely an interface callback method, which is the specific logic to be completed by your 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 the thread so that a thread object can 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, and 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 in the interrupted state, but also ensures that the thread returns non-interrupted state before, 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, the specified sleep time (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 talk about letting the current job 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, it cannot be called]. 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.
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 & 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 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 (http://blog.csdn.net/celineshi/archive/2007/06/28/1670354.aspx)