Java multi-thread programming detailed

xiaoxiao2021-03-06  94

One: Understanding Multithreading Multithreading is a mechanism that allows multiple instruction streams to be executed in the program, each instruction stream is called a thread, which is independent of each other. The thread is also called a lightweight process, and it has independent execution control as the process. The operating system is responsible for scheduling, the difference is that the thread has no separate storage, but shares a storage space with other threads in the process, which makes Communication between threads is far from the process. The execution of multiple threads is concurrent, which is logically "simultaneous", regardless of whether it is physical "simultaneous". If there is only one CPU, then the real "simultaneous" is impossible, but because the speed of the CPU is very fast, the user does not feel the difference, so we don't have to care about it, only need to envisure the threads simultaneously . Multi-threaded and traditional single-threading in programming the biggest difference is that since the control flows of each thread are independent of each other, the code between each thread is executed, resulting in thread scheduling, synchronization, etc. It will be discussed later.

2: Implementing multi-thread in Java, we may wish to make a new thread, what do we need to do? Obviously, we must indicate the code to be performed by this thread, and this is everything we need to do in Java!   is 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: Inherit the Thread class, override the method Run (), and we override Run (), join the code to be executed in the subclass of the THREAD class. Here 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, it is in line with everyone's habits, but it also has a big shortcoming, then Just 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, 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 we have to use this new method, isn't it to avoid inheritance?) Java provides interface java.lang.Runnable to support this method. Method 2: Implementing the Runnable interface Runnable interface only one method run (), we declare that our class implements the runnable interface and provides this method, write our thread code to it, complete this part of the task. But the runnable interface does not have any support for threads, and we must also create an instance of the Thread class, which is implemented through the constructor of the Thread class.

Here is an example: public class mythread us 1, number; public mythread (int Num) {Number = NUM; System.out.Println ("Create Thread" Number); 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 ();}}                                                                                                                                 Yes, the subclass must not cover the RUN method of the Thread class, otherwise the thread will be the RUN method of the subclass, not the RUN method we used to implement 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 compactly with multiple classes in most cases. 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: The four states of threads 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   thread priority representing the importance of the thread, when multiple threads are in executable and wait for the CPU time, the thread scheduling system determines who all the threads according to the priority of each thread. CPU time, high priority thread has a greater opportunity to get CPU time, priority, low threads, no chance, just the opportunity to be small. You can call the Thread class GetPriority () and setPriority () to access the priority of the thread, between 1 (MIN_PRIORIRIRIRIRIRITY), default is 5 (Norm_Priority).

5: Synchronization of threads   Since multiple threads of the same process share the same storage space, it also brings convenience, and 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 (int newval); 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 class instance, otherwise The gear is blocked. Once the method is executed, the lock is exclusively until the lock is released until it returns from the 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. Syntax is as follows: synchronized (syncObject) {// the code to allow access control} synchronized block is a block of code, which must be the object code SyncObject (as described above, can be a class instance or class) of the lock in order Execution, the specific mechanism will be described as previously described. Since any code block can be arbitrarily specified, the flexibility is higher.

Six: Threads of threads   In order to resolve access conflicts on shared storage area, Java introduced synchronization mechanism. Now let's examine multiple threads to share resources, obviously synchronized mechanisms are not enough, because at any time required The resources are not necessarily ready to be accessed, in turn, the resources ready to prepare more. In order to solve access control problems in this case, Java introduced support for blocking mechanisms. 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 very 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 are nothing to do 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 very simple, only in the synchronized method or block current thread, only The 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 characteristics of the Wait () and Notify () methods determine that they are often used together with the Synchronized method or block, and the inter-process communication machine between them and the operating system will find their similarities: SYNCHRONIZED method or block Functions similar to operating system primitives are provided, and 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: Calling the notify () method causes the thread that releases the blocking of blocking to be randomly selected from the thread that is blocked by the Wait () method called the object. We cannot expect which thread will be selected, so you should be particularly careful when programming, avoiding 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 are blocked due to the Wait () method of the object. The disposable is all released. Of course, only the thread that gets the lock can enter the executable state. To talk about blocking, you can't talk about a deadlock. If you can find a slight analysis, you can find that the call () method and the call of 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 function is most powerful, but this is also caused They have a lower efficiency, more prone to errors. In actual use, we should use various methods in order to better meet our goals. Seven: Guarding threads is a special thread. Its and normal threads differ in it is not the core part of the application, and when all non-daemon threads of an application terminate, even if there is still a guarding thread Operation, the application will also terminate, in turn, as long as there is a non-standard thread running, 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.

8: Thread groups are a Java unique concept. In Java, the thread group is an object of the THREADGROUP, each with a unique thread group, this thread group specifies and in the thread You cannot be changed during the entire life. You can specify the thread group of the thread belonging by calling the Thread class constructor containing the ThreadGroup type parameters. If no specified, thread defaults to system thread groups called System. In Java, in addition to the pre-built system thread group, all thread groups must be explicitly created. 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 to start or block all threads. 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? Multi-threaded core lies in multiple code blocks and implementation, essentially characteristics between the code between the blocks is executed. 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 to 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 one The loop is simple and efficient, nor does it need 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 uses multithreading. worth it.

转载请注明原文地址:https://www.9cbs.com/read-107652.html

New Post(0)