2: Implement multithreading in Java
We may wish to think about what we need to do in order to create a new thread? Obviously, we must indicate the code to be performed by this thread, and this is everything we need to do in Java!
It's amazing! How does Java do this? By class! As a full-scale object, Java provides class java.lang.Thread to facilitate multi-threaded programming, which provides a large number of ways to facilitate our control of our threads, and we will be carried around this class.
So how do you provide the code we want to thread to java? Let's take a look at the Thread class. The most important way to THREAD class is Run (), which is called for the Thread class, and provides the code to be performed by our thread. In order to specify our own code, just override it!
Method 1: Inheriting the Thread class, coverage method Run ()
We rewrite Run (), join the code to be executed in the subclass of the Thread class.
Below is an example:
Public class mythread extends thread {
INT count = 1, Number;
Public mythread (int Num) {
Number = NUM;
System.out.Println ("Create Thread" Number;
}
Public void run () {
While (true) {
System.out.println ("Thread" Number ": Count" Count);
IF ( count == 6) return;
}
}
Public static void main (string args []) {
For (int i = 0; i <5; i ) new mythread (i 1) .Start ();
}
}
This method is simple and clear, in line with everyone's habits, but it also has a big shortcoming, that is, if our class has inherited from a class (such as a small program must inherit from the Applet class), you can't inherit the Thread class. At this time, if we don't want to build a new class, what should I do?
We may wish to explore a new way: we don't create a subclass of the Thread class, but use it directly, then we can only pass our method as a parameter to the Thread class instance, a bit similar to the callback function. But Java does not have a pointer, we can only pass an instance of classes that contain this method. So how do you limit this class to include this method? Of course, use the interface! (Although the abstract class can also be satisfied, it is necessary to inherit, and the reason why we have to use this new method is to avoid the restrictions brought by inheritance?)
Java provides interface java.lang.Runnable to support this method.
Method 2: Implement Runnable interface
The RunNable interface has only one method run (), we declare that our class implements the runnable interface and provides this method, and write our thread code to the task of this part.
But the runnable interface does not have any support for threads, we must also create an instance of the Thread class, this point through the constructor of the Thread class
Public Thread (Runnable Target);
Below is an example:
Public class mythread implements runnable {
INT count = 1, Number;
Public mythread (int Num) {
Number = NUM;
System.out.Println ("Create Thread" Number;
}
Public void run () {
While (true) {
System.out.println ("Thread" Number ": Count" Count);
IF ( count == 6) return;
}
}
Public static void main (string args []) {
For (int i = 0; i <5; i ) New Thread (New Mythread (i 1)). start ();
}
}
Strictly speaking, an example of creating Thread subclasses is also possible, but it must be noted that the subclass must not cover the RUN method of the Thread class, otherwise the thread will be the RUN method of the subclass, not me
They use the RUN method of the class of the runnable interface, you may wish to test it.
Using the runnable interface to implement multithreading makes us to include all the code in a class, which is conducive to the package, it's a disadvantage that we can only use a set of code, if you want to create multiple threads and make each thread perform different code The classes must still be created additionally. If this is, in most cases, it is better to inherit Thread is compact.
In summary, both methods have a thousand autumn, everyone can be flexible.
Let's take a look at some of the problems in multi-threaded use.
Three: four states of thread
1. New Status: The thread has been created but has not been executed (start () has not been called).
2. Execute Status: Threads can be executed, although not necessarily being implemented. The CPU time may be assigned to the thread at any time, making it execute.
3. Death Status: Run () returns the thread to death. Calling STOP () or destroy () also has the same effect, but it is not recommended, the former will produce an exception, the latter is forced to terminate and does not release the lock.
4. Blocking Status: The thread will not be assigned a CPU time and cannot be executed.
4: Thread priority
The priority of the thread represents the importance of the thread. When multiple threads are in executable and wait for the CPU time, the thread scheduling system determines the priority of each thread to assign CPU time, high priority. There is a greater chance to get the CPU time, the priority low thread is not there, just the opportunity to be small.
You can call the Thread class method getPriority () and setPriority () to access the thread priority, the thread is between 1 (Min_Priority) and 10 (Max_Priority), default is 5 (Norm_Priority).
Five: Synchronization of threads
Since multiple threads of the same process share the same storage space, it also brings convenience, it also brings a serious problem of accessing conflicts. The Java language provides a special mechanism to address this conflict, effectively avoiding the same data objects to be accessed simultaneously by multiple threads.
Since we can guarantee data objects through the private key, we can only be accessed by way, so we only need to make a set of mechanisms for the method, this mechanism is the synchronized keyword, which includes two usage: Synchronized method and Synchronized block. 1. Synchronized method: Declare the Synchronized method by adding the synchronized keyword in the method declaration. Such as:
Public Synchronized Void AccessVal;
Synchronized method controls access to class member variables: Each class instance corresponds to a lock, each Synchronized method must obtain the lock of the class instance of the method that calls the method, otherwise the thread is blocked,
Once the law is performed, the lock is exclusively until it will be released until it returns from this method, and the block is blocked, and the lock can be re-entered. This mechanism ensures that at the same time for each class instance, all of which is in the member function of Synchronized, is in an executable state (because at most one can get the corresponding lock), effectively avoid the class member. Variables Access Conflict (as long as all methods that may access class member variables are declared as synchronized).
In Java, not only a class instance, each class also corresponds to a lock so that we can also declare the class's static member function as synchronized to control its access to the static member variables of the class.
Synchronized method: If a big method declares that Synchronized will greatly affect efficiency, typically, if the thread type method Run () is declared as synchronized, since it has been running during the entire life of the thread, It will lead to the call to any SYNCHRONIZED method in this class will never succeed. Of course, we can declare this issue by placing the code of the access class member variables in a special method, and call this problem in the main method, Java provides us with better solution, that is SYNCHRONIZED block.
2. Synchronized block: Declare the Synchronized block by synchronized keyword. The syntax is as follows:
Synchronized (SyncObject) {
// Allow access to the control code
}
The SYNCHRONIZED block is such a code block, where the code must be obtained by the object SyncObject (as described above, can be a class instance or class), and the specific mechanism will be described as previously described. Since any code block can be arbitrarily specified, the flexibility is higher.
Six: Blocking of threads
In order to resolve access conflicts on the shared storage area, Java introduced synchronization mechanism. Now let's examine access to multiple threads on shared resources, clearly the synchronization mechanism is not enough, because the resources required at any time are not necessarily ready The resource that is accessed, in turn, the resource prepared at the same time may also be more than one. In order to solve access control problems in this case, Java introduced support for blocking mechanisms.
The blocking refers to the execution of a thread to wait for a certain condition (such as a resource ready), and classmates who have learned the operating system must be familiar with it. Java provides a large number of ways to support blocking, and let us analyze one by one.
1. Sleep () method: SLEEP () allows you to specify a period of time as a parameter in milliseconds, which enters the blocking state in the specified time, cannot get the CPU time, the specified time is over, the thread is re-entered status. Typically, Sleep () is used in situations waiting for a certain resource: After the test discovery conditions are not met, the thread blocks the thread to retest and retest until the condition satisfies.
2. Suspend () and resume () Method: Two methods are used, suspend () enables the thread to enter the blocking state, and does not automatically recover, must be called to be called to re-enter the executable state . Typically, Suspend () and resume () are used in situations that are waiting for another thread to generate results: After the test results have not yet occurred, the thread is blocked, and the other thread has a result, calling resume () to restore it. .
3. Yield () method: yield () makes the thread to discard the currently outstanding CPU time, but does not cause threads to block, that is, the thread is still in executable, and may separate the CPU time again. The effect of calling Yield () is equivalent to the scheduler thinks that the thread has executed enough time to go to another thread.
4. Wait () and notify (): Two methods are used, Wait () makes the thread into the blocking state, there are two forms, one for a period of time to specify in milliseconds as a parameter, the other Parameters, the former When the corresponding Notify () is called or beyond the specified time, the thread re-enters the executable, the latter must be called.
It seems that they have no differences between them with suspend () and resume () methods, but in fact they are very different. The core is that all methods of the previously described, and it does not release the lock (if occupied) is blocked, and this pair method is reversed.
The core difference of the above results in a series of details.
First, all the methods described above are affiliated to the Thread class, but this pair is directly affiliated to the Object class, that is, all objects have this pair. It is very incredible, but it is actually very natural, because this pair method is blocked when the lock is blocked, and the lock is any object, and the Wait () method of calling any object causes the thread to block. And the lock on the object is released. The NOTIFY () method calling any object is caused by a random selection in the thread that is incorporated by the WAIT () method of the object (but to wait until the lock is really executable).
Second, all the methods described above can be called anywhere, but this pair of methods must be called in the synchronized method or block, the reason is also very simple, only in the synchronized method or the current thread holds the lock, only lock Can be released. The same truth, the lock on the object called this pair must be owned for the current thread, so that the lock can be released. Therefore, this pair method call must be placed in such a SYNCHRONIZED method or block, the method or block of the block is called the object of this pair of methods. If this condition is not met, the program can still be compiled, but IllegalMonitorStateException exception occurs at runtime.
The above features of the WAIT () and Notify () methods determine that they are often used together with the Synchronized method or block, and the process between the processes between them and the operating system will find their similarities: Synchronized method or block provides Similar to the function of operating system primitives, their execution is not interfered by multi-thread mechanism, and this pair method is equivalent to block and wakeup primitives (this pair method is declared as synchronized). Their combination allows us to implement a series of exquisite processes on a series of exquisite processes (such as signal algorithms) and is used to address various complex thread communication issues. About Wait () and Notify () methods will then explain two points:
First: Call the notify () method causes the thread that is blocked by the clogging from the thread that is blocked by the Wait () method called the object, we cannot expect which thread will be selected, so it is especially careful when programming. Avoid problems due to this uncertainty.
Second: In addition to NOTIFY (), there is also a method notifyAll () can also play a similar role, the only difference is that all threads that call the notifyAll () method will block all threads that block the Wait () method of the object. All release block. Of course, only the thread that gets the lock can enter the executable state.
When you talk about the blocking, you can't talk about a deadlock. You can find that the SUSPEND () method and the call of the wait () method and the WAIT () method that do not specify the timeout period may result in a deadlock. Unfortunately, Java does not support the avoidance of deadlocks at the language level, we must carefully avoid dead locks in programming.
We have analyzed the various methods of achieving thread blocking in Java. We focus on the WAIT () and Notify () methods because their features are most powerful, but this also leads them. The efficiency is low, it is more likely to be wrong. In actual use, we should use various methods in order to better meet our goals.
Seven: Dazhi Thread
The guarding thread is a special thread. Its and normal threads are not the core part of the application. When all the non-daemon threads of an application are terminated, even if there is still a guarding thread running, the application will also Termination, it is, as long as there is a non-standard thread to run, the application will not terminate. The daemon is generally used to provide services for other threads in the background.
You can determine whether a thread is a daemon by calling method isDaemon (), or you can call method setDaemon () to set a thread as a daemon.
Eight: thread group
The thread group is a Java unique concept. In Java, the thread group is an object of THReadgroup, each thread is affiliated with a unique thread group, which is specified in the thread and cannot be used during the thread. change. You can specify the thread group of the thread belonging by calling the Thread class constructor containing the ThreadGroup type parameters. If there is no specified, thread defaults to system thread group named System.
In Java, all thread groups must be explicitly created in addition to the pre-built system thread group.
In Java, each thread group except the system thread group is also part of another thread group, you can specify the thread group members belonging when you create a thread group. If you do not specify, it is default to the system thread group. . In this way, all thread groups form a tree with a system thread group.
Java allows us to operate simultaneously with all threads in a thread group, such as we can set all the threads of all threads by calling the corresponding ways of the thread group, or all threads can be started or blocked.
Another important role of Java's thread group mechanism is thread security. The thread group mechanism allows us to distinguish between threads with different security features, different processing of threads of different groups, and can also support the use of unsuitable safety measures through the hierarchy of thread groups. The Java's ThreadGroup class provides a large number of ways to facilitate our operation of each of the thread groups in the thread group and each thread in the thread group.
Nine: Summary
In this lecture, we have learned all aspects of Java multi-threaded programming, including creating threads, and scheduling, managing multiple threads. We have a deep understanding of the complexity of multi-thread programming, as well as the inefficiency of multi-threaded programs brought by thread switching, which also prompted us to seriously think about a problem: Do we need multi-thread? When will I need multi-thread?
The core of the multi-thread is that the multiple code blocks are implemented, and the essential features are the code between the blocks. Does our program need multi-thread, it is to see if this is also its intrinsic feature.
If our programs do not require multiple code blocks and implement, it will naturally do not need to use multithreaded; if our program requires multiple code blocks to implement, but we don't ask for trouble, we can use a loop. Simple and efficiently, it is not necessary to use multithreading; only when it is fully compliant with multi-threaded features, multi-threading mechanisms have strong support for communication and thread management in line-building, which is worthwhile. .