Multi-threaded programming I (the basis of Java multithreading) and multi-threaded programming
I. Concepts of processes and threads
Process:A program is called a process. Each process has independent code and data space. The overhead of inter-process switching is large. A process contains 1-n threads. A process is the smallest unit of resource sharing.
Thread:The same class of threads share code and data space. Each thread has an independent running stack and program counter (PC). The thread switching overhead is small, and the thread is the minimum unit of CPU scheduling.
Multi-process:The operating system can run multiple tasks (programs) at the same time ).
Multithreading:Multiple sequential streams are executed in the same program, and the thread is a single control sequence stream within the process.
Threads and processes are in the same status: creation, ready, running, blocking, and destruction. 1. New: A New thread object is created. 2. ready state (Runnable): After a thread object is created, other threads call the start () method of the object. The thread in this status is located in the runable thread pool and becomes runable, waiting to obtain the CPU usage right. 3. Running status (Running): The ready thread obtains the CPU and executes the program code. 4. Blocking status (Blocked): the blocking status indicates that the thread gives up CPU usage for some reason and stops running temporarily. It is not until the thread enters the ready state that it has the opportunity to go to the running state. Blocking is divided into three types: (1) waiting for blocking: The Running thread executes the wait () method, and the JVM puts the thread into the waiting pool. (Wait releases the lock held) (2) Synchronization blocking: When a running thread obtains the synchronization lock of an object, if the synchronization lock is occupied by another thread, then JVM will put this thread into the lock pool. (3) Other blocking: When the running thread executes the sleep () or join () method or sends an I/O Request, JVM sets the thread to blocking. When the sleep () status times out, the join () waits for the thread to terminate or times out, or the I/O processing is completed, the thread enters the ready state again. (Note: sleep does not release the lock held.) 5. Dead state (Dead): The thread ends its life cycle after the thread is executed or the run () method is exited due to an exception.
Ii. Advantages of Multithreading
A single thread is characterized by queuing for execution, that is, synchronization. Multithreading can use the free time of the CPU to process other tasks to the maximum extent, and the system running efficiency is greatly improved. multithreading is used to execute Asynchronization.
3. Multithreading
There are two main methods to implement multi-threaded programming: one is to inherit the Thread class and the other is to implement the Runable interface. In fact, when creating a new Thread by inheriting the Thread class, the biggest limitation is that multi-inheritance is not supported, because the Java language features a single inheritance, so in order to support multi-inheritance, the Runnable interface can be fully implemented, while inheritance is implemented. However, the threads created by these two methods are of the same nature at work and there is no essential difference.
Public class Thread1 extends Thread {private int count = 5; @ Override public void run () {for (int I = 0; I <2; I ++) {System. out. println ("now a thread" + currentThread (). getName () + "executing:" + count --);}}}
Public class Thread2 implements Runnable {private int count = 5; @ Override public void run () {for (int I = 0; I <2; I ++) {System. out. println ("now a Thread" + Thread. currentThread (). getName () + "executing:" + count --);}}}
Public class Test {public static void main (String [] args) {// integrates Thread class Thread1 thread1 = new Thread1 (); Thread t1 = new Thread (thread1, "A"); Thread t2 = new Thread (thread1, "B"); Thread t3 = new Thread (thread1, "C"); t1.start (); t2.start (); t3.start (); // implement the Runable interface Thread2 thread2 = new Thread2 (); Thread t4 = new Thread (thread2, "A2"); Thread t5 = new Thread (thread2, "B2"); Thread t6 = new Thread (thread2, "C2"); t4.start (); t5.start (); t6.start ();}}
This result is used to describe the following two points:
1. the CPU is uncertain about thread scheduling and adopts "preemptive" scheduling.
2. threads that implement the Runnable interface can share data, but threads that inherit the Thread cannot. In fact, the difference between them is only the limitation of single inheritance and some usage differences (for example, if you want to do something else for this Thread object (such as getName ), then you must call the Thread. the currentThread () method gets reference to this thread), there is no substantive difference.
Why is the start () method rather than the run () method called during multi-thread execution? If the code thread. run () is not asynchronously executed but synchronized, the thread object will not be handed over to the "thread scheduler" for processing. Instead, the main thread calls the run () method. That is to say, you must wait until the code in the run () method is executed. Start () is used to start a thread. When the start () method is called, the system starts a thread through start () in Thead class () the thread to be started is in the ready state (runable State), and is not running at this time. Once the CPU time slice is obtained, the run () method is automatically started. 4. synchronized keywords
Multi-threaded lock mechanism, by adding the synchronized keyword before the method to be called by multiple threads, multiple threads should first try to get the lock when executing the method. If the lock can be obtained, then this thread can execute the code in synchronize. If the lock cannot be obtained, the thread will continuously try to get the lock until it gets the lock. Synchronized can lock any object or method, and the code used for locking is called "mutex" or "critical section ".
The synchronized keyword is used to ensure that the current thread is not preemptible by other threads during execution and the shared resources are modified, leading to thread insecurity.
5. common thread Methods
1,Thread. currentThread () method: return the information of the Thread that is calling the code segment. The most common is Thread. currentThread (). getName ().
2,IsAlive () method: checks whether the current thread is active. What is the activity status? The active State means that the thread has been started and has not been terminated. When a thread is running or is ready to start running, the thread is considered to be "alive.
3,Thread. sleep () method: sleep the "Running Thread" (paused) within a specified millisecond ). This "executing thread" refers to the thread returned by this. currentThread.
4,GetId () method: gets the unique identifier of the thread.
5,Thread. interrupt () method: Used to interrupt a Thread. Pay attention to the Thread here. the role of interrupt is not to interrupt the thread, but to "notice the thread should be interrupted". Whether the thread is interrupted or continues to run should be handled by the notified thread. Specifically, when interrupt () is called for a thread,
① If the thread is in the congested State (for example, sleep, wait, join, etc.), the thread will immediately exit the blocked state, throw an InterruptedException exception, and clear the interrupt flag, to false.
② If the thread is in normal activity, the thread interrupt flag is set to true. The thread with the interrupt mark set will continue to run normally and will not be affected.
Thread thread = new Thread ()-> {while (! Thread. interrupted () {// check whether the interrupt flag is set to true or program logic. Do not use obsolete threads. stop, Thread. suspend, Thread. resume // do more work .}}); thread. start (); // thread after a period of time. interrupt ();
It is worth mentioning that there are two ways to determine whether a thread is interrupted:
- Interrupted (): checks whether the current thread is in the interrupted state. After execution, the thread can clear the status mark as false. (Note that even MyThread. interrupted () is used to test the status of the current thread ).
- IsInterrupted (): checks whether the Thread object is in the interrupted state, but does not clear the status mark.
Thread interruption by throwing an exception:
Public class MyThread extends Thread {@ Override public void run () {try {for (int I = 0; I <500000; I ++) {if (this. interrupted () {System. out. println ("stopped! I want to exit "); throw new InterruptedException ();} System. out. println ("I =" + (I + 1) ;}} catch (InterruptedException e) {System. out. println ("Enter MyThread. catch in the java class run method! "); E. printStackTrace ();}}}
In addition, you can use the retuen method to interrupt the thread. However, we recommend that you "throw an exception" to stop the thread, because the exception can be thrown up in the catch block so that the thread stop event can be propagated.
6,Thread. yield () method: discard the current CPU resource and give it to other tasks to occupy the CPU execution time. However, the time for giving up is uncertain. It is possible that you just gave up and immediately obtain the CPU time slice.
7,SetPriority () method: MAX_PRIORITY, NORM_PRIORITY, and MIN_PRIORITY are recommended for program portability. Setting the priority does not mean that the call is not available if the priority is low, but the CPU prefers to execute the higher priority first, but the thread that the CPU calls cannot be determined, setting priority can only ensure that the thread is called frequently.
8,SetDaemon (true): Specifies the daemon thread. A daemon is a special thread. Its features are "companion". When there is no non-daemon thread in the process, the daemon thread is automatically destroyed. A typical daemon thread is the garbage collection thread. When there is no non-daemon thread in the process, the garbage collection thread is unnecessary.
9,Join () method: Wait for the thread to terminate. The join () method is mainly used to let the thread that calls this method complete the items in the run method, and then execute the code after the join () method, for join () A method call can be interrupted by calling the interrupt () method on the thread.
Vi. Others
1,Stop () method void: If the thread is forced to stop, some cleanup tasks may not be completed. Another scenario is to "unlock" the locked object, resulting in data not being synchronized and data inconsistency.
2,The suspend () method suspends the thread. Resume the thread execution by using the resume () method.
3,When using suspend () and resume (), improper use can easily lead to exclusive public synchronization objects, making other threads unable to access public synchronization objects. For example, if data is not synchronized due to thread suspension, suspend and resume will exclusively lock the resource access (I ++ has no lock and println () has a synchronization lock ).