Ali p9 teaches you to understand the principle of Java multithreading in three minutes

Foreword
Thread pool, hence the name suggests, is a pool for storing threads. To put it more academically, it is a collection of thread resources. Why is there a concept of thread pool? Think about it before, when we all need threads, we directly create one manually, and then we don’t care about it after executing the task. The thread is a tool or carrier for us to perform asynchronous tasks. We don’t pay much attention to the thread itself. The impact of the life cycle on the system or the environment, and only focuses on the output of the results of the execution of multi-threaded tasks, and then the goal is achieved, but the maintenance and monitoring of thread resources are truly ignored. With the use of a large number of multi-threaded resources in large-scale systems, the lack of attention to, maintenance and management of multi-threading has gradually expanded its impact on resource occupation and reduced performance, which aroused people's thinking.

  1. List item

The creation and destruction of multi-threads occupies a large proportion in the life cycle of multi-threads. This part actually takes up resources and performance. If threads are used to perform simple tasks, the maintenance cost of threads has exceeded the benefits of task execution. It is not worth the loss, so a thread pool is created. Through the use of thread pools, the life cycle of threads can be controlled, and threads can be easily obtained, reused, and additional performance overhead caused by frequent creation and destruction of threads can be avoided. This is probably the background and original intention of the introduction of thread pools.

1. Multi-thread creation method
1.1. Inherit the Thread class to create the thread class
1. Implementation steps
Define a subclass that inherits the Thread class and override the run() method of this class;

Create an instance of the Thread subclass, that is, create a thread object;

Call the start() method of the thread object to start the thread.

2.核心代码
`class SomeThead extends Thraad { public void run() { //do something here
}
}

public static void main(String[] args){ SomeThread oneThread = new SomeThread();
//启动线程
oneThread.start(); }`

1.2. Implement the Runnable interface to create a thread class
1. Implementation steps
Define the implementation class of the Runnable interface and rewrite the run() method of the interface;

Create an instance of the Runnable implementation class, and use this instance as the target object of Thread, that is, the Thread object is the real thread object.

2.核心代码
class SomeRunnable implements Runnable { public void run() { //do something here } } Runnable oneRunnable = new SomeRunnable(); Thread oneThread = new Thread(oneRunnable); oneThread.start();

1.3. Create a thread through Callable and Future
1. Implementation steps
Create an implementation class of the Callable interface and implement the call() method. The modified method will be the thread execution body and have a return value.

Create an instance of the Callable implementation class, and use the FutrueTask class to wrap the Callable object. The FutureTask object encapsulates the return value of the call() method of the Callable object

Use the FutureTask object as the target of the Thread object to create and start a new thread

Call the get() method of the FutureTask object to obtain the return value after the execution of the child thread ends.

2. Core code
`//1. Create the implementation class of the Callable interface and implement the call() method public class SomeCallable01 implements Callable {@Override public Integer call() throws Exception {int i = 0; for(;i<10; i++) {System.out.println(Thread.currentThread().getName()+" "+i);} return i;}

public static void main(String[] args) { //2. Create an instance of the Callable implementation class SomeCallable01 ctt = new SomeCallable01();

//3.使用FutrueTask类进行包装Callable对象,FutureTask对象封装了Callable对象的call()方法的返回值
FutureTask<Integer> ft = new FutureTask<>(ctt);

//开启ft线程
for(int i = 0;i < 21;i++)
{
    System.out.println(Thread.currentThread().getName()+" 的循环变量i的值"+i);
    if(i==20)//i为20的时候创建ft线程
    {
    	//4.使用FutureTask对象作为Thread对象的target创建并启动新线程
        new Thread(ft,"有返回值的线程FutureTask").start();
    }
}

//ft线程结束时,获取返回值
try
{	
	//5.调用FutureTask对象的get()方法获取子线程执行结束后的返回值。
    System.out.println("子线程的返回值:"+ft.get());//get()方法会阻塞,直到子线程执行结束才返回
} catch (InterruptedException e)
{
    e.printStackTrace();
} catch (ExecutionException e)
{
    e.printStackTrace();
}

}
Copy code
}`

Second, the difference between the ways of creating threads
1. Use the inherited Thread class to create multiple threads
1) Advantages It is
simple to write. If you need to access the current thread, you don't need to use the Thread.currentThread() method. You can use this directly to get the current thread.

2) Disadvantages The
thread class has inherited the Thread class, so it can no longer inherit from other parent classes. (There are limitations of single inheritance)

When creating multiple threads, each task has member variables that are not shared, and static must be added to achieve sharing

2. Use the method of implementing the Runnable class to create multithreading
1) Advantages It
avoids the limitations of single inheritance. Multiple threads can share a target object, which is very suitable for multithreading to process the same resource.

2) Disadvantages are
more complicated, access to the thread must use the Thread.currentThread () method, no return value.

3. Use the method of implementing the Callable interface to create multiple threads
1) Advantages It
has a return value, avoids the limitations of single inheritance, and multiple threads can share a target object, which is very suitable for multi-threaded processing of the same resource.

2) Disadvantages are
more complicated, and you must use the Thread.currentThread() method to access the thread

4. The difference between Runnable and Callable
1) Callable stipulates (override) method is call(), Runnable stipulates (override) method is run().

2) Callable tasks can return values ​​after execution, but Runnable tasks cannot return values.

3) The call method can throw exceptions, but the run method cannot.

4) Run the Callable task to get a Future object, which represents the result of asynchronous calculation. It provides a method to check whether the calculation is complete, to wait for the completion of the calculation, and to retrieve the result of the calculation. Through the Future object, you can understand the execution of the task, cancel the execution of the task, and get the execution result future.get().

3. Multi-thread scheduling
3.1. Scheduling strategy
Time slice: thread scheduling adopts time slice rotation. Preemptive type: high-priority thread preempts the CPU

3.2. Java scheduling method
1) For threads of the same priority to form a first-in first-out queue (first come, first served), use the time slice strategy

2) For high priority, use the preemptive strategy of priority scheduling

3.3, the thread priority
level:

MAX_PRIORITY:10

MIN_PRIORITY:1

NORM_PRIORITY:5

method:

`getPriority(): return thread priority

setPriority(int newPriority): Change the priority of the thread`

Remarks:

High-priority threads must preempt the CPU execution rights of low-priority threads. But only in terms of probability, high-priority threads are more likely to be executed. It does not mean that only high-priority threads are executed before low-priority threads are executed.

4. Multithreaded state management
4.1. Thread sleep-sleep
1) Overview
If we need to pause the currently executing thread for a period of time and enter the blocking state, we can call the sleep method of Thread.

2) Thread sleep method
Put the executing thread to sleep within the specified number of milliseconds:

sleep(long millis) Sleeps the executing thread within the specified number of milliseconds plus the specified number of nanoseconds:

sleep(long millis,int nanos)

3) The code implementation
sleep is a static method, it is best not to call it with the instance object of Thread, because it sleeps the thread that is currently running, not the thread object that calls it. It is only valid for the thread object in the running state. .

`public class SynTest { public static void main(String[] args) { new Thread(new CountDown(),“倒计时”).start(); } }

class CountDown implements Runnable{ int time = 10; public void run() { while (true) { if(time>=0){ System.out.println(Thread.currentThread().getName() + “:” + time–); try { Thread.sleep(1000); //睡眠时间为1秒 } catch (InterruptedException e) { e.printStackTrace(); } } } } }`

4) Remarks
Java thread scheduling is the core of Java multithreading. Only good scheduling can give full play to the performance of the system and improve the execution efficiency of the program. But no matter how the programmer writes the schedule, it can only affect the order of thread execution to the greatest extent, but cannot achieve precise control. Because after using the sleep method, the thread enters the blocking state, and only when the sleep time is over, will it re-enter the ready state, and the ready state enters the running state, which is controlled by the system, and we cannot accurately interfere with it. , So if you call Thread.sleep(1000) to make the thread sleep for 1 second, the result may be greater than 1 second.

4.2. Thread concession-yield
1) Overview The
yield() method is similar to the sleep() method. It is also a static method provided by the Thread class. It can also pause the currently executing thread and give up cpu resources to others Thread. But unlike the sleep() method, it does not enter the blocking state, but enters the ready state. The yield() method just makes the current thread pause, re-enter the ready thread pool, and let the system's thread scheduler reschedule again. It is entirely possible that this situation: when a thread calls the yield() method, The thread scheduler schedules it out again to enter the running state for execution.

In fact, when a thread calls the yield() method to suspend, the priority is the same as that of the current thread, or a thread with a higher priority than the current thread's ready state is more likely to get a chance of execution. Of course, it is just possible. Because it is impossible for us to precisely interfere with the CPU scheduling thread.

2) Code implementation
public class Test1 { public static void main(String[] args) throws InterruptedException { new MyThread("low level", 1).start(); new MyThread("intermediate", 5).start(); new MyThread("Advanced", 10).start(); } }





class MyThread extends Thread { public MyThread(String name, int pro) { super(name);// Set the name of the thread this.setPriority(pro);// Set the priority }



@Override  
public void run() {  
    for (int i = 0; i < 30; i++) {  
        System.out.println(this.getName() + "线程第" + i + "次执行!");  
        if (i % 5 == 0)  
            Thread.yield();  
    }  
}  

}
Copy code
3) The difference between sleep and yield
①After the sleep method suspends the current thread, it will enter the blocking state. Only when the sleep time is up, will it enter the ready state. After the yield method is called, it directly enters the ready state, so it may just enter the ready state and be scheduled to the running state.

②The sleep method statement throws InterruptedException, so when calling the sleep method, the exception must be caught, or the display statement throws the exception. The yield method does not declare that a task exception is thrown.

③The sleep method has better portability than the yield method, and usually do not rely on the yield method to control the execution of concurrent threads.

4.3. Thread merging—join
1) Overview
The meaning of thread merging is to merge the threads of several parallel threads into a single thread for execution. The application scenario is that when one thread must wait for another thread to execute before it can execute, the Thread class provides The join method is used to complete this function. Note that it is not a static method.

in short:

​ When the B thread executes the .join() method of the A thread, the B thread will wait, and the B thread will execute when the A thread is completed. join can be used to temporarily join threads for execution.

2) Thread merge method
It has three overloaded methods:

​ The current thread waits for it to join the thread and waits for the thread to terminate.

void join()

​ The longest time the current thread waits for the thread to terminate is millis milliseconds.

​ If the thread is not executed within millis time, then the current thread enters the ready state and waits for the cpu scheduling again

void join(long millis)

​ The longest waiting time for this thread to terminate is millis milliseconds + nanos

​ Nanoseconds. If the thread is not executed within millis time, then the current thread enters the ready state and waits for the cpu scheduling again

void join(long millis,int nanos)

3) Code implementation
public static void main(String[] args) throws InterruptedException { yieldDemo ms = new yieldDemo(); Thread t1 = new Thread(ms,"Zhang San is left after eating"); Thread t2 = new Thread(ms ,"Li Si has left after eating"); Thread t3 = new Thread(ms,"Wang Wu has left after eating"); t1.start(); t1.join();





    t2.start();
    t3.start();
    System.out.println( "主线程");
}`

Thread t = new Thread(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
r = 10;
});

t.start();
// Let the main thread block and wait for the t thread to execute before continuing
// Remove the line, the execution result is 0, plus the execution result of the line is 10
t.join();
log.info(" r:{}”, r);

// Run result
13:09:13.892 [main] INFO thread.TestJoin-r:10
Copy code
4.4, set thread priority
1) Overview
Each thread has a priority attribute when it is executed, the thread with high priority Can get more execution opportunities, while threads with low priority get fewer execution opportunities. Similar to thread sleep, thread priority still cannot guarantee the execution order of threads. However, threads with high priority have a higher probability of acquiring CPU resources, and threads with low priority are not without the opportunity to execute.

The default priority of each thread has the same priority as the parent thread that created it. By default, the main thread has normal priority.

2) Involving priority methods The
Thread class provides setPriority(int newPriority) and getPriority() methods to set and return the priority of a specified thread. The parameter of the setPriority method is an integer, ranging from 1 to ·0. You can use the three static constants provided by the Thread class:

MAX_PRIORITY =10 MIN_PRIORITY =1 NORM_PRIORITY =5

3) Code implementation
public class Test1 { public static void main(String[] args) throws InterruptedException { new MyThread("high level", 10).start(); new MyThread("low level", 1).start(); } }




class MyThread extends Thread {  
    public MyThread(String name,int pro) {  
        super(name);//设置线程的名称  
        setPriority(pro);//设置线程的优先级  
    }  
    @Override  
    public void run() {  
        for (int i = 0; i < 100; i++) {  
            System.out.println(this.getName() + "线程第" + i + "次执行!");  
        }  
    }  
}

Copy code
4) Remarks
Although Java provides 10 priority levels, these priority levels require the support of the operating system. The priority of different operating systems is not the same, and it does not correspond well to the 10 priority levels of Java. So we should use MAX_PRIORITY, MIN_PRIORITY and NORM_PRIORITY three static constants to set the priority, so as to ensure the best portability of the program.

4.5. Background (daemon) threads
1) Overview The
use of daemon threads is rare, but they are not useless. For example, threads such as garbage collection and memory management of JVM are all daemon threads. There is also the database connection pool used when doing database applications. The connection pool itself also contains many background threads to monitor the number of connections, timeout period, status, and so on.

By default, the java process needs to wait for all threads to end before it ends. There is a special thread called a daemon thread. When all non-daemon threads are finished, even if it is not finished, it will be forced to end.

2) Involving methods
Call the method setDaemon(true) of the thread object to set it as a daemon thread.

Mark the thread as a daemon thread or a user thread. When the running threads are all daemon threads, the Java virtual machine exits. This method must be called before starting the thread. This method first calls the checkAccess method of the thread without any parameters. This may throw a SecurityException (in the current thread).

public final void setDaemon(boolean on)
Parameters: on-If true, mark the thread as a daemon thread.
Throws:
IllegalThreadStateException-if the thread is active.
SecurityException-if the current thread cannot modify the thread.

3) Purpose of the
daemon thread The daemon thread is usually used to perform some background tasks, such as playing background music while your application is running, and doing automatic grammar checking and automatic saving in a text editor.

Java's garbage collection is also a daemon thread. The advantage of the guard line is that you don't need to care about its ending. For example, you want to play background music when your application is running. If you set the thread that plays background music to a non-daemon thread, then when the user requests to exit, not only must exit the main thread, but also notify the background music to play The thread exits; if it is set as a daemon thread, it is not needed.

4.6. Stop the thread
1) Overview
Thread.stop(), Thread.suspend, Thread.resume, Runtime.runFinalizersOnExit These methods of terminating thread running have been abandoned, and it is extremely unsafe to use them.

The correct way to stop the thread:

​ First: The run method is executed normally, and then it ends.

​ Second: Control the loop condition and the identifier of the judgment condition to end the thread.

2)实现代码示例
class MyThread extends Thread { int i=0; boolean next=true; @Override public void run() { while (next) { if(i==10) next=false; i++; System.out.println(i); } } }

4.7. Thread interruption—interrupt
1) What is interrupt (interrupt)?
Interrupt is just a cooperative mechanism. Java does not add any syntax to interrupt. The interrupt process completely needs to be implemented by programmers themselves;

​ Each thread object has a flag, which is used to indicate whether the thread is interrupted; the flag bit is true to indicate interruption, and false to indicate uninterrupted;

​ Set the thread's flag to true by calling the interrupt method of the thread object; it can be called in other threads or in its own thread.

Interruption flag: whether the thread is interrupted, true means it is interrupted, false means not

2) Involving the method
isInterrupted() method:

Get the interruption mark of the thread (check which thread object is called), the interruption mark of the thread will not be modified after the call

interrupt() method:

Interrupt this thread (which thread object is called to interrupt who). If the thread that needs to be interrupted is in a blocked state (sleep, wait, join), then its interrupted state will be cleared, and an exception (InterruptedException) will be thrown. This interruption is not really stopping the thread, but setting its interruption state to "stopped" state, the thread will continue to run, as to how to stop the thread, we still have to stop it by ourselves, this method is just to stop the thread The state of is set to the "stop" state, which is true.

Interrupt a normal thread, the thread will not be interrupted, but the interruption of the thread is marked as true.

interrupted() method:

Check whether the current thread is interrupted, and use it in conjunction with the interrupt() method above. The interruption status of the thread will be cleared by this method, that is to say: if this method is successfully called twice in succession, the second time

The call will return false (unless the current thread is interrupted again after the first call and before the second call).

In other words: clear the interrupt flag after the call, that is, if it gets true, the interrupt flag after the call is false (not commonly used)

4.8. Thread blocking
Thread blocking can be divided into many types. The definition of blocking at the operating system level and the Java level may be different, but in a broad sense, there are several ways to block threads:

1) BIO blocking, that is, a blocking io stream is used

2) sleep(long time) let the thread sleep into a blocking state

3) a.join() The thread calling this method enters blocking, waiting for the a thread to finish executing and resume running

4) sychronized or ReentrantLock causes the thread to enter the blocked state without acquiring the lock

5) Calling the wait() method after acquiring the lock will also make the thread enter the blocking state

6) LockSupport.park() allows the thread to enter the blocking state

V. Summary of thread core methods
5.1. Correspondence between the six thread states and methods

Insert picture description here

5.2. Summary of thread core methods
1) Core methods in the Thread class
2) Thread-related methods in Object
Insert picture description here

to sum up
Insert picture description here

Many people have been interviewing recently. I have compiled multiple copies here: Java multithreading materials, Spring family bucket (1187 pages of documents), Java systemized materials: (including the latest Java core knowledge points in 2021, java interview topics and Internet real questions, e-books, etc. summarized in 21 years), friends in need can join the QQ group "748945508" to get them for free.

Guess you like

Origin blog.csdn.net/dcj19980805/article/details/114693244