[Java Learning Summary] Multithreading

1. Thread introduction

1. What is a process:

A process is the running process of a program and an independent unit for the system to allocate and schedule resources. In layman's terms, a process is a program running in an operating system, such as WeChat, eclipse, idea, etc. running in a computer.

2. What is a thread

A thread is the smallest unit that an operating system can perform operation scheduling. A process has at least one thread, and a program can have multiple threads.

3. Multithreading

A program is multithreaded if it can run multiple threads at the same time. For example, when watching a video, the program simultaneously loads images, obtains subtitles and obtains barrage, etc.

Second, the creation of threads

1. Inherit the Thread class

step:

(1) Create a thread class and inherit the Thread class
(2) Rewrite the run() method, write the thread execution body
(3) Create a thread object, and call the start() method to start the thread. The
sample code is as follows:

public class TestThread extends Thread{
    
    
    @Override
    public void run() {
    
    
        //重写run方法线程执行体
        for (int i = 0; i < 100; i++) {
    
    
            System.out.println("testThread线程第"+i+"次执行");
        }
    }
    public static void main(String[] args) {
    
    
    	//创建线程对象
        TestThread testThread = new TestThread();
        //调用start()方法开启线程
        testThread.start();//子线程开启,和主线程交替执行
        //main线程执行一个for循换
        for (int i = 0; i < 100; i++) {
    
    
            System.out.println("main线程第"+i+"次执行");
        }
    }
}

The execution result is shown in the figure below. The testThread and main threads will be executed 100 times alternately. Part of the output is intercepted.

2. Implement the Runnable interface

step:

(1) Define the MyRunnable class to implement the Runnable interface
(2) Implement the run() method and write the thread execution body
(3) Create the implementation class object of the Runnable interface
(4) Create a thread object and call the start() method to start the thread
. The sample code is as follows:

public class TestRunnable implements Runnable{
    
    
    @Override
    public void run() {
    
    
        //重写run方法线程体
        for (int i = 0; i < 100; i++) {
    
    
            System.out.println("testRunnable线程第"+i+"次执行");
        }
    }
    public static void main(String[] args) {
    
    
        //创建Runnable接口的实现类对象
        TestRunnable testRunnable = new TestRunnable();
        //创建线程对象,通过线程对象来开启我们的线程,代理
        Thread thread = new Thread(testRunnable);
        //调用start方法,启动线程
        thread.start();//子线程开启,和主线程交替执行
		//main线程执行for循换
        for (int i = 0; i < 100; i++) {
    
    
            System.out.println("main线程第"+i+"次执行");
        }
    }
}

Execution result The two threads testThread and main will be executed alternately 100 times, which is the same as the previous program.

3. Implement the Callable interface

Step
(1) Implement the Callable interface, which needs to return the type of value
(2) Rewrite the call method, which needs to throw an exception
(3) Create the target object (4
) Create the execution service
(5) Submit for execution
(6) Get the result
(7) Close Serve

public class TestCallable implements Callable<Boolean> {
    
    
    //重写call方法
    @Override
    public Boolean call() {
    
    
        for (int i = 0; i < 100; i++) {
    
    
            System.out.println("testCallable线程执行了"+i);
        }
        return true;
    }
    public static void main(String[] args) throws ExecutionException, InterruptedException {
    
    
        TestCallable testCallable = new TestCallable();
        //创建执行服务
        ExecutorService service = Executors.newFixedThreadPool(1);
        //提交执行
        Future<Boolean> future = service.submit(testCallable);
        //获取结果
        Boolean result = future.get();
        //关闭服务
        service.shutdownNow();
    }
}

3. Thread state

1. Five states of threads

(1) New state (New): After the thread object is created, it enters the new state. Execution
(2) Ready state (Runnable): After calling the start() method of the thread object, the thread enters the ready state. At this time, the thread enters the waiting queue and may be scheduled for execution by the CPU at any time.
(3) Running state (Running): When the run method is executed, the thread obtains the CPU permission to execute and enters the running state.
(4) Blocked state (Blocked): The blocked state means that the thread gives up the right to use the CPU for some reason and temporarily stops running. When the program is running, it will enter the blocking state when it encounters sleep, wait, join and other methods or fails to acquire the synchronization lock.
(5) Dead state (Dead): The thread finishes its execution or exits the run() method due to an exception, and the thread ends its life cycle.

2. Thread state diagram:

insert image description here

3. Thread stop

  • When a thread's run() method finishes executing, the thread will terminate naturally.
  • JDK provides stop(), destroy() methods (not recommended).
  • It is recommended to define a Boolean variable flag as a flag bit. When flag=false, the thread is terminated.
public class TestStop implements Runnable{
    
    
	//1.设置一个标志位
    private boolean flag = true;
    @Override
    public void run() {
    
    
        while (flag){
    
    
            System.out.println("run...Thread");
        }
    }
    //2.设置一个公开的方法停止线程,转移标志位
    public void stop(){
    
    
        this.flag = false;
    }
}

4. Thread blocking and waiting

(1) Thread sleep

  • Calling the sleep() method in the Thread class can realize the sleep of the thread.
  • Overloading of the sleep method: sleep(long millis) can pass in the sleep time, in milliseconds. That is, let the current thread sleep for millis millis milliseconds. The sleep(long millis, int nanos) method makes the current thread sleep for millis millis + nanos nanoseconds.
  • The thread enters the blocked state (Blocked) before the sleep time is reached.
  • After the sleep time is up, the thread enters the ready state (Runnable).
  • sleep can simulate network delay, countdown, etc.
  • When the thread sleeps, the lock is not released.

(2) Politeness of threads

  • Calling the yield() method in the Thread class can realize the politeness of the thread.
  • Polite thread, so that the currently executing thread is suspended, but does not enter the blocked state (Blocked). After executing the yield method, it is still in the ready state (Runnable).
  • A polite thread actually gives up the chance of this execution and lets the CPU reschedule. Of course, the CPU's next scheduling may be to execute other threads, or this thread may be scheduled. Which thread is scheduled to execute next time is random.

(3) Merging of threads

  • Call the join() method in the Thread class to merge threads.
  • Merge threads, merge multiple threads into one. It is to execute the thread that calls the join() method first, and then execute other threads after the thread is executed.
  • When this thread executes first, other threads enter the blocked state (Blocked).

5. Observation of thread state

The getState() method in the Thread class observes the state of the thread and provides a return value to obtain the state of the thread.

4. Thread synchronization

1 Overview

(1) What is concurrency?
Concurrency: The same object is operated by multiple threads at the same time.
(2) Why thread synchronization is required?
Concurrent phenomena are often encountered in daily life. The same object is modified by many thread operations at the same time. For example, when the ticket grabbing software is grabbing tickets, thousands of users buy tickets at the same time. If thread synchronization is not performed at this time, it will lead to extremely confusing operations on objects.
The best solution to this situation in life is to let everyone line up to operate one by one. Similarly, thread synchronization can also be introduced in our threads. Thread synchronization is actually a waiting mechanism, and multiple users need to access this object at the same time. The threads enter the waiting pool of this object to form a queue, wait for the previous thread to be used up, and then the next thread will use it.

2. Synchronization methods and synchronization blocks

  • The synchronized keyword is locking. When a thread manipulates the object, it will get the lock, and then if other threads want to manipulate the object, it will enter the blocked state (Blocked). Until the previous thread finishes manipulating the object and releases the lock, subsequent threads can acquire the lock and operate on the object.
  • Example: When buying a ticket, one person comes first to buy the ticket. During the ticket buying process, other people cannot operate the ticket and must enter the queuing state. After waiting for the previous person to buy tickets, the people behind can start buying tickets. This operation can prevent two people from buying duplicate tickets.
  • The synchronized keyword includes two usages: synchronized method and synchronized block.

(1) synchronized method

A synchronized method can be implemented by adding the synchronized modifier to the method.
Disadvantages: Only the content that needs to be modified in the method needs to be locked. This method locks too much and wastes resources.

    private synchronized void buy() throws InterruptedException {
    
    
       /*
       方法体
       */
    }

(2) synchronized block

synchronized (obj){
    
    
	/*
	方法体
	*/
}

Where obj is the object that needs to be locked. To modify which object, just lock which object.

3. Thread deadlock

(1) The concept of deadlock

For example: A thread occupies test1 resource, B thread occupies test2 resource. If at this time, A thread must call the test2 resource occupied by B to continue execution, then A needs to enter the blocking state, and wait for the end of B thread to release the lock of test2 before continuing execution. If it happens that thread B also needs the test1 resource occupied by thread A at this time, then both threads A and B will enter the blocked state at the same time, and both need to wait for the other party to finish executing, and the program will freeze. This situation becomes a thread deadlock.

(2) Ways to avoid deadlock

Four necessary conditions for a deadlock to occur:

  • Mutual exclusion: A resource can only be used by one process at a time.
  • Request and hold conditions: When a process is blocked due to requesting resources, it will hold on to the obtained resources.
  • Non-deprivation condition: The resources obtained by the process cannot be forcibly deprived until they are used up.
  • Circular waiting condition: A head-to-tail circular waiting resource relationship is formed among several processes.

V. Summary

1. The difference between the run() method and the start() method:

  • Call the start() method to start the thread; call the run method, which is an ordinary method call and will not start a new thread.
  • Calling the start() method has multiple execution paths, and the main thread and sub-threads execute alternately; calling the run() method has only one execution path for the main thread.

2. The difference between yield and sleep:

  • sleep() is to enter the blocking state first, and then enter the ready state after the end. yield() is to enter the ready state directly.
  • Yield() will give the same or higher priority a higher chance of execution.

Guess you like

Origin blog.csdn.net/qq_43647936/article/details/120802262