This is the 27th day of my participation in the August Genwen Challenge.More challenges in August

| author: jiangxia

| CSDN:blog.csdn.net/qq_41153943

| the nuggets: juejin. Cn/user / 651387…

| zhihu: www.zhihu.com/people/1024…

| GitHub:github.com/JiangXia-10…

This article is about 7,679 words and takes 16 minutes to read

preface

Process and thread are two very basic and important concepts in operating system, and they are one of the knowledge points that we must ask in pen interview. Today this article will sort out the light thread and process related knowledge points.

01 Basic Concepts of threads

A pen interview usually asks: What is a process and what is a thread? What are the differences and relationships between them?

A process is the basic unit of resource allocation (CPU, memory, etc.) and is an instance of a program at execution time. When the program is running, the system creates a process, allocates resources to it, and then puts the process in the ready queue. When the process scheduler selects it, it allocates CPU time to it, and the program actually runs.

The thread is a part of the process, is an execution path, is the smallest unit when the program is executed, it is an execution flow of the process, is the basic unit of CPU scheduling and dispatching, a process can be composed of many threads, threads share all the resources of the process, each thread has its own stack and local variables. Threads are scheduled independently by the CPU, allowing multiple threads to run simultaneously in a multi-CPU environment. Concurrent operations can also be performed by multithreading, with one thread assigned to each request.

A running software (such as wechat, QQ, etc.) is a process, and a process can run multiple tasks at the same time (for example, we can use wechat and QQ to video chat with others at the same time, or type chat, they are respectively a process), so we can simply consider the process as a collection of threads.

A thread is a path that can be executed. Multithreading is the simultaneous execution of multiple execution paths.

The process thread model in the system looks like this:

Processes get their basic memory from the operating system, and all threads share the process’s memory address space. Of course, each thread also has its own private memory address range that other threads cannot access.

Since all threads share the memory address space of the process, communication between threads is much easier by sharing process-level global variables.

Threads are abstractly described in JAVA using the Thread class. Threads have the following six states:

  • NEW: the state of a thread that has just been created but has not yet been started.

  • RUNNABLE: Thread status of RUNNABLE threads;

  • BLOCKED: The thread state of a thread that is BLOCKED and waiting for a monitor lock;

  • WAITING: the state of a thread WAITING for a thread;

  • WAITING: a thread that is WAITING for a thread;

  • TIMED_WAITING: Thread state of a waiting thread with a specified wait time;

  • TERMINATED: the thread ends execution and is TERMINATED.

Public number before there is an article, specifically about the six states of the thread: the six states of the thread, there is a need for students, you can view this article.

02 Creating and starting a thread

In Java, Thread represents threads. All Thread objects must be instances of Thread or a subclass of Thread. Threads can be created in Java in four ways, as follows:

1) Create a Thread by inheriting the Thread class

2) Implement the Runnable interface to create threads

3) Create threads using Callable and Future

4) Use thread pools, such as the exExecutor framework

1.Thread class inheritance

When a Thread starts, it calls the run method, so you can define a Thread class by overriding the run method of the Thread class.

package Demo1; public class MyThread extends Thread{ @Override public void run(){ System.out.println("hello world"); } public static void main(String[] args) { MyThread myThread = new MyThread(); myThread.start(); }}Copy the code

Running results:

2. Implement Runnable interface

The implementation class that defines the Runnable interface also overwrites the run() method, which, like the run() method in Thread, is the execution body of the Thread

package Demo1; public class MyThread1 implements Runnable { @Override public void run() { System.out.println("hello world"); } public static void main(String[] args) { Thread thread = new Thread(new MyThread1()); thread.start(); }}Copy the code

Running results:

Copy the code

Thread extends from the Runnable interface and provides a default implementation of the run method:

@Overridepublic void run() { if (target ! = null) { target.run(); }}Copy the code

Target is a field of type Runnable that is initialized by the Thread constructor. So when the thread starts, the run method called will be the run method of our own implementation class.

Create threads using Callable and Future

Unlike the Runnable interface, the Callable interface provides a call() method as the thread body, which is more powerful than the run() method.

  • The call() method can have a return value

  • The call() method can declare an exception to be thrown

Java5 provides the Future interface to represent the return value of the Call () method in the Callable interface and an implementation class, FutureTask, that implements both the Future and Runnable interfaces. Therefore, it can be used as a target for the Thread class. Several public methods are defined in the Future interface to control the Callable tasks it is associated with.

Boolean cancel(Boolean mayInterruptIfRunning) : V get() # return the value of call () in the Callable. This method will block the program until the child thread ends. Throw TimeoutException V get(long timeout,TimeUnit Unit) Return True Boolean isDone() # True Boolean isCancelled() if the Callable task isCancelled before it completes properly.Copy the code

Creating and starting a thread with a return value using Callable and Future actually creates the implementation class for the Callable interface and implements the clall() method. We use the FutureTask class to wrap the Callable implementation object and use the FutureTask object as the target of the Thread object to create the Thread. The specific steps are as follows:

1. Create an implementation class for the Callable interface, implement the Call () method, and then create an instance of that implementation class. (Starting with Java8, you can create Callable objects directly using Lambda expressions.)

2. Use the FutureTask class to wrap the Callable object, which encapsulates the return value of the Callable object’s call() method

Create and start threads using FutureTask as the target of Thread objects (because FutureTask implements the Runnable interface)

4. Call FutureTask’s get() method to get the return value after the child thread completes execution

package Demo1; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; public class MyThread2 { public static void main(String[] args) { Callable<Integer> myCallable = new MyCallable(); FutureTask<Integer> ft = new FutureTask<Integer>(MyCallable); // Use FutureTask to wrap MyCallable object for (int I = 0; i < 100; i++) { System.out.println(Thread.currentThread().getName() + " " + i); if (i == 30) { Thread thread = new Thread(ft); //FutureTask creates a new Thread thread.start() as the target of the Thread object; }} system.out. println(" The main thread for loop completes..") ); try { int sum = ft.get(); Println ("sum = "+ sum); system.out.println ("sum =" + sum); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } } class MyCallable implements Callable<Integer> { private int i = 0; // Unlike the run() method, the call() method has a return value @override public Integer call() {int sum = 0; for (; i < 100; i++) { System.out.println(Thread.currentThread().getName() + " " + i); sum += i; } return sum; }}Copy the code

Some running results are as follows:

Use thread pools, such as the exExecutor framework

Java provides four thread pools through Executors:

1. NewCachedThreadPool Creates a cacheable thread pool. If the length of the thread pool exceeds the required length, you can recycle idle threads.

2. NewFixedThreadPool Creates a fixed-length thread pool that controls the maximum number of concurrent threads. The excess threads will wait in the queue.

3. NewScheduledThreadPool Creates a thread pool of fixed length that supports scheduled and periodic task execution.

4. Create a single threaded newSingleThreadExecutor thread pool, it will only use the only worker thread to perform the task, to ensure all tasks in specified order (FIFO, LIFO, priority).

package Demo1; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class MyThread3 { public static void main(String[] args) { ExecutorService executorService = Executors.newSingleThreadExecutor(); for(int i=0; i<5; Executorservice.execute (()->{system.out.println (thread.currentThread ().getName()+" executorService.execute "); }); } system.out.println (" thread task starts executing "); executorService.shutdown(); }}Copy the code

The main way to create threads is to use the previous two methods.

03 Other thread-related methods

The Thread class also provides other methods for manipulating threads.

1, sleep.

public static native void sleep(long millis)
Copy the code

Thread.sleep(Long millis) static methods force currently executing threads to sleep(that is, suspend execution). When a thread sleeps, it sleeps somewhere and does not return to a runnable state until it wakes up. When the sleep time expires, it returns to an operational state. So, the sleep() method specifies the minimum time for which the thread will not run. When the sleep time ends, the thread returns to the runnable state. Note that the thread is not in the running state. If the thread is in the running state, it needs to wait for the CPU to schedule execution.

package Demo1; public class Thread4 { public static void main(String[] args) { Runner1 r1 = new Runner1(); Thread t = new Thread(r1); t.start(); for (int i = 0; i < 3; i++) { System.out.println("main thread :"+i); } } } class Runner1 implements Runnable{ @Override public void run() { try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } for (int i = 0; i < 3; i++) { System.out.println("Runner1 : " + i); }}}Copy the code

2, start

public synchronized void start()
Copy the code

I was wondering why the Runnable run method was overridden to specify the work of the thread, but the thread was started by the start method.

Starting a thread is not just a matter of giving an instruction start entry. The operating system also needs to divide a part of the shared memory space of the process into private resources for the thread, create program counters, stacks and other resources, and finally call the run method. This is like a car running mainly engine, but the engine is not good, must use the key to start. The start here is just like start(); Run () is like an engine.

This is often asked about the difference between the start and run methods.

3, interrupt

public void interrupt()
Copy the code

Call interrupt() to tell the thread that it should interrupt

1. If a thread is blocked, it immediately exits the blocked state and throws an InterrupedException.

2. If the thread is active, the interrupt flag of the thread is set to true. Threads with interrupt flags continue to run in the middle of the session, unaffected.

The thread to be called is required to cooperate with the interrupt

1. Check the interrupt flag of the thread frequently during the normal running of the task. If the interrupt flag is set, the thread will stop itself.

Note: Calling interrupt() does not interrupt the thread, but sets the thread’s interrupt flag to true

package Demo1; public class MyThread4 { public static void main(String[] args) throws InterruptedException { Runnable interruptTask = new Runnable() { int i = 0; Override public void run() {Override public void run() {Override public void run() {Override public void run() {Override public void run() { Thread.currentthread ().isinterrupted ()){ i++; System.out.println(Thread.currentThread().getName() + " (" + Thread.currentThread().getState() + ") loop " + i); }} Catch (InterruptedException e){// Correctly handle InterruptedException when calling a blocking method. (For example, the thread terminates after a catch.) System.out.println(Thread.currentThread().getName() + " (" + Thread.currentThread().getState() + ") catch InterruptedException."); }}}; Thread t1 = new Thread(interruptTask,"t1"); System.out.println(t1.getName() +" ("+t1.getState()+") is new."); // Start "thread t1" t1.start(); System.out.println(t1.getName() +" ("+t1.getState()+") is started."); // The main thread sleeps for 300ms, and then the main thread issues the interrupt instruction to T1. Thread.sleep(300); t1.interrupt(); System.out.println(t1.getName() +" ("+t1.getState()+") is interrupted."); // Sleep the main thread for 300ms, then check the status of T1. Thread.sleep(300); System.out.println(t1.getName() +" ("+t1.getState()+") is interrupted now."); }}Copy the code

The running results are as follows:

4, the join

public final synchronized void join(long millis)
Copy the code

This method is usually called from another thread, indicating that the current thread needs to block in the current position, waiting for the target thread to complete all instructions. For example, thread.Join adds the specified thread to the current thread. It is possible to merge two alternating threads into sequential threads. For example, if thread B calls thread A’s Join() method, thread B will not continue executing until thread A finishes executing.

package Demo1;public class ThreadDemo5 {    public static void main(String[] args) {        Thread t = new Thread(new RunnableImpl());        t.start();        try {            t.join(1000);            System.out.println("joinFinish");        } catch (InterruptedException e) {            e.printStackTrace();        }    }}class RunnableImpl implements Runnable {    public void run() {        try {            System.out.println("Begin sleep");            Thread.sleep(1000);            System.out.println("End sleep");        } catch (InterruptedException e) {            e.printStackTrace();        }    }}
Copy the code

The running results are as follows:

Begin sleep
joinFinish
End sleep
Copy the code

When the main thread calls t. jin, the main thread waits for t thread, and the wait time is 1000.

04 summary

Process as the basic unit of system allocation of resources, and thread is a part of the process, sharing the resources in the process, and thread is the smallest execution flow of system scheduling. In the real-time system, each thread gets the time slice to call the CPU, and multi-threads use the CPU simultaneously. Each context switch corresponds to the “operation site” saving and recovery, which is also a relatively time-consuming operation.

Click here for a retrospective

Getting started: SpringBoot integrates Freemarker and Thymeleaf templates

SpringBoot Getting Started: Build your first SpringBoot project using IDEA and Eclipse

SpringBoot integrates JPA for data access

SpringBoot integration Druid configuration data source monitoring