Java multi-thread analysis and java Analysis
The cause of the problem is a simple interview question: the question requirements are as follows:
Create three threads, thread A prints 10 times A, thread B prints 10 times B, and thread C prints 10 times C. The thread must run simultaneously and print 10 times ABC alternately.
Before solving the problem, we should add some basic knowledge:
Runnable and Thread startup
Thread startup does not simply call your RUN method. Instead, a thread scheduler calls the RUN methods of all your threads separately,
Our normal RUN method will not return if it is not completed, that is, it will continue to be executed, so that the methods below the RUN method will not be executed, however, the RUN method in the thread is not the same. It only takes a certain amount of CPU time. After the thread is executed, it will be sent to other threads. In this way, the CPU time is repeatedly switched, because the switching speed is fast, we feel that multithreading is running at the same time.
You do not have this effect when calling the run method. Therefore, you must call the start method of the Thread class to start your Thread. Therefore, you have two methods to start the Thread.
First, write a class that inherits from the Thread class, then override the run method in it, and start the Thread using the start method.
Second, write a class to implement the Runnable interface and implement the run method in it. Use the new Thread (Runnable target). start () method to start
Both methods must implement the RUN method. When the thread starts, the thread manager will call your RUN method.
Relationship between start () and run ()
Start a Thread by calling the start () method of the Thread class,
This thread is in the ready state,
Not running.
Then, the Thread class calls the method run () to complete its operation,
Here the run () method is called the thread body,
It contains the content of the thread to be executed,
The Run method is finished,
This thread is terminated,
The CPU then runs other threads,
If you directly use the Run method,
This is just to call a method,
The program still has only the main thread-this thread,
There is only one program execution path,
In this way, the write thread is not achieved.
Differences
The Thread class is defined in the java. lang package. As long as a class inherits the Thread class and overwrites the run () method in this class, it can implement multi-threaded operations. However, a class can only inherit one parent class, which is the limitation of this method.
Implementing the Runnable interface has the following significant advantages over inheriting the Thread class:
(1) It is suitable for multiple threads with the same program code to process the same resource, effectively separating the virtual CPU (thread) from the program code and data, it better reflects the object-oriented design philosophy.
(2) avoid restrictions caused by Java's single inheritance feature. We often encounter this situation, that is, when we want to put sub-classes that have inherited a class into multithreading, because a class cannot have two parent classes at the same time, therefore, we cannot inherit the Thread class, so this class can only implement the Runnable interface.
(3) It is conducive to program robustness. The code can be shared by multiple threads, and the code and data are independent. When the Execution Code of multiple threads comes from instances of the same class, that is, they share the same code. Multiple Threads operate on the same data, regardless of their code. When shared access has the same object, that is, they share the same data. When a thread is constructed, the required code and data are passed through an object as the real parameter of the constructor. This object is an instance of the class that implements the Runnable interface.
During the test, I found that the threads are sequential when inheriting the Thread, and the threads are indeed unordered when Runnable is implemented.
Wait, policy, and sleep
Obj. wait (), and Obj. notify () must be used with synchronized (Obj), that is, wait. It is used with notify to operate on the Obj lock that has been obtained. In terms of syntax, It is Obj. wait (), Obj. Y must be in synchronized (Obj ){...} within the statement block. In terms of function, wait means that the thread actively releases the object lock after obtaining the object lock, and the thread sleep. You can continue to obtain the object lock and continue to execute the lock until notify () of an object is invoked by another thread. The corresponding notify () is the wake-up operation on the object lock. However, it is important to note that after policy () is called, the object lock is not released immediately, but after the execution of the corresponding synchronized () {} statement block ends and the lock is automatically released, JVM randomly selects a thread from the thread of the wait () object lock, assigns it an object lock, wakes up the thread, and continues execution. This provides synchronous and wake-up operations between threads. Thread. sleep () and Object. both wait () and wait () can suspend the current thread and release CPU control. The main difference is that the Object. wait () releases the control of the object lock while releasing the CPU.
For the sleep () method, we first need to know that the method belongs to the Thread class. The wait () method belongs to the Object class.
The sleep () method causes the program to pause the execution for the specified time, giving way to other threads of the cpu, but its monitoring status remains unchanged. When the specified time reaches, the program will automatically resume running.
When the sleep () method is called, the thread does not release the object lock.
When the wait () method is called, the thread will discard the object lock and enter the waiting lock pool for this object. Only notify () is called for this object () this thread enters the object lock pool.
With this knowledge, let's solve the problem.
Question Analysis
We can get several key points from the question:
1: The thread runs simultaneously: But there is no requirement for thread startup
2: Each thread prints 10 corresponding letters
3: Alternate printing: it means that the printing operations of the three threads are strictly ordered.
Train of Thought Analysis
1: Each thread prints different letters. The operation is similar. It can be implemented using a unified class and initialized by itself without any need.
2: There is A sequence between threads. If the thread that prints A is printed, the thread that prints B can print it.
How to Ensure the order of execution between threads is a challenge in this question,
Breakthrough
The printing thread should enter the waiting state after printing A, until the printing thread of C prints C once and then re-executes
The threads for printing B and C are similar.
Simple thinking
Define three objects to traverse a, B, and c. Each thread obtains the three Object locks at the same time before printing the corresponding letters. After printing, release the locks of the other two objects.
Problem
Each thread needs to get three Object locks at the same time to print. The first thread finishes printing. If only the lock of the other two objects is released, no thread can continue printing;
If all three are released, the current thread can continue printing.
Therefore, the idea of using three Object locks does not seem to work.
One of the correct ideas (there may be other ideas)
Each thread can print its own letters only once it obtains the Lock of its own and its own prefix objects (for example, A's prefix is C and B's is, then, release the lock of the prefix object and enter the waiting thread pool of the front-end object. After the prefix object is awakened, the printing can continue.
When will the object with its own prefix be awakened?
A simple idea is to print the thread of A and enter the thread pool waiting for the C object after printing A. Just print the thread of C and wake up when printing itself, the thread that prints A can print A immediately after the thread that prints C;
After you print your own prefix, immediately wake up yourself, release the lock of your own prefix object, and enter the waiting thread pool of your front-end object so that your suffix thread can be printed immediately and cyclically, the problem seems to have been solved.
Potential problems
Since each thread only has two locks and only waits for one lock, there are still requirements on the thread startup sequence. If the Starting sequence is ACB, let's analyze it:
Thread A: Obtain the AC two locks at the beginning, print A, wake up A, enter the thread pool waiting for C to be awakened, and release the AC
Thread B: obtain two AB locks at the beginning, print B, wake B, enter the thread pool waiting for A to be awakened, and release AB
Thread C: Get the BC two locks at the beginning, print the C, wake up the C, enter the thread pool waiting for B to be awakened, and release the BC
This is completely correct, so we must ensure that the thread corresponding to the print ABC starts sequentially.
The practice is simple: Just run sleep for A while after starting.
new Thread(aThread).start();// Thread.sleep(10); new Thread(bThread).start();// Thread.sleep(10); new Thread(cThread).start();// Thread.sleep(10);
If your class is implements Runnable, the sequence in which the three threads start is not guaranteed,
Of course, you can change it to extends Thread. In this case, these three threads are started sequentially.
The complete implementation code is as follows:
/***** @ Author Qi Weijie * @ version November 20, 2015 10:15:07 */public class MyThreadPrint implements Runnable {private String name; private Object prev; private Object self; public MyThreadPrint (String name, Object prev, Object self) {// TODO Auto-generated constructor stub this. name = name; this. prev = prev; this. self = self ;}@ Override public void run () {// TODO Auto-generated method stub int count = 10; while (count> 0) {synchronized (prev) {synchronized (self) {System. out. print (name); count --; // self. optional Y ();} try {prev. wait ();} catch (InterruptedException e) {// TODO Auto-generated catch block e. printStackTrace () ;}}} public static void main (String [] args) throws InterruptedException {Object a = new Object (); Object B = new Object (); object c = new Object (); MyThreadPrint aThread = new MyThreadPrint ("a", c, a); MyThreadPrint bThread = new MyThreadPrint ("B", a, B ); myThreadPrint cThread = new MyThreadPrint ("c", B, c); new Thread (aThread ). start (); // Thread. sleep (10); new Thread (bThread ). start (); // Thread. sleep (10); new Thread (cThread ). start (); // Thread. sleep (10); // aThread. run (); // bThread. run (); // cThread. run ();}}
P