Java multithreading - introduction to three ways of creation

Multithreading

Introduction to Multithreading

What is a thread ?

A thread is an execution path within a program.

After we started the program execution before, the execution of the main method is actually a separate execution path.

public static void main(String[] args) {
     
     
  	// 代码...
  	for (int i = 0; i < 10; i++) {
     
     
      	System.out.println(i);
		}
  	// 代码...
}

If there is only one execution path in the program, then the program is a single-threaded program.

What is multithreading ?

Multithreading refers to the technology of implementing multiple execution processes from hardware and software.

Multi-threaded creation

Method 1: Inherit the Thread class

Thread class :

Java represents threads through the java.lang.Thread class.

According to the object-oriented thinking, the Thread class should provide a way to achieve multi-threading.

The Thread class creates a thread method :

  1. Define a subclass MyThread to inherit the thread class java.lang.Thread
  2. Rewrite the run() method in the subclass MyThread
  3. Create an instance object of the MyThread class
  4. Call the start() method of the child thread object to start the thread (the run method is still executed after startup)

The Thread class creates a multi-threaded sample code as follows :

public class ThreadDemo {
    
    
    public static void main(String[] args) {
    
    
        // 3. 创建MyThread类的实例对象
        Thread t = new MyThread();
        // 4. 调用子线程对象的start方法启动线程(启动后还是执行的run方法)
        t.start();

        // 主线程中执行的操作
        for (int i = 0; i < 5; i++) {
    
    
            System.out.println("主线程执行输出: " + i);
        }
    }
}

/**
    1. 定义一个线程类继承自Thread
 */
class MyThread extends Thread {
    
    
    /**
        2. 重写run方法, run方法中定义创建出来的线程要做什么
     */
    @Override
    public void run() {
    
    
        for (int i = 0; i < 5; i++) {
    
    
            System.out.println("子线程执行输出: " + i);
        }
    }
}

The Thread class has disadvantages of creating multiple threads :

Pros: Easy to code

Disadvantages: The thread class has inherited Thread and cannot inherit other classes, which is not conducive to expansion; if the thread has an execution result, it cannot be returned directly, which means that if the rewritten run method has a return value, there is no way to get it. This method Only suitable for performing functions.

As mentioned above, the run method is still executed after calling the start method, so why not directly execute the run method ?

Calling the run method directly will be executed as a normal method, which is equivalent to single-threaded execution at this time.

Only calling the start method starts a new thread for execution.

Note: Do not put the code of the main thread executing tasks before the sub-threads, because the sub-threads are always started after the main thread has finished running, which is equivalent to the effect of a single thread.

Method 2: Implement the Runnable interface

The way to create multithreading by implementing the Runnable interface is as follows :

  1. Define a thread task class MyRunnable to implement the Runnable interface
  2. Override the run() method in the task class MyRunnable
  3. Create MyRunnable task class object
  4. Hand over the MyRunnable task object to Thread for processing.
  5. Call the start() method of the thread object to start the thread

Implement the Runnable interface to create multi-threaded sample code :

public class ThreadDemo2 {
    
    
    public static void main(String[] args) {
    
    
        // 3. 创建MyRunnable 任务对象
        Runnable target = new MyRunnable();
        // 4. 把任务对象交给线程对象(Thread)处理
        Thread t = new Thread(target);
        // 5. 启动线程
        t.start();

        // 主线程要执行的操作
        for (int i = 0; i < 5; i++) {
    
    
            System.out.println("主线程执行输出: " + i);
        }
    }
}

/**
    1. 定义一个线程任务类, 实现Runnable接口
 */
class MyRunnable implements Runnable {
    
    
    /**
        2. 任务类MyRunnable中重写run方法
     */
    @Override
    public void run() {
    
    
        for (int i = 0; i < 5; i++) {
    
    
            System.out.println("子线程执行输出: " + i);
        }
    }
}

Implementing the Runnable interface to create multi-threaded, anonymous inner classes means simplified method 1 :

public static void main(String[] args) {
    
    
    // 1. 创建任务对象(匿名内部类的方式)
    Runnable target = new Runnable() {
    
    
        @Override
        public void run() {
    
    
            for (int i = 0; i < 5; i++) {
    
    
                System.out.println("子线程执行输出: " + i);
            }
        }
    };
    // 2. 将任务对象交给线程对象(Thread)处理
    Thread t = new Thread(target);
    // 3. 启动线程
    t.start();

    // 主线程执行的操作
    for (int i = 0; i < 5; i++) {
    
    
        System.out.println("主线程执行输出: " + i);
    }
}

Implementing the Runnable interface to create multi-threaded, anonymous inner classes means simplifying the second method :

public static void main(String[] args) {
    
    
    // 1. 创建任务对象(匿名内部类的方式)
    // 2. 将任务对象交给线程对象(Thread)处理
    // 3. 启动线程
    new Thread(new Runnable() {
    
    
        @Override
        public void run() {
    
    
            for (int i = 0; i < 5; i++) {
    
    
                System.out.println("子线程执行输出: " + i);
            }
        }
    }).start();

    // 主线程执行的操作
    for (int i = 0; i < 5; i++) {
    
    
        System.out.println("主线程执行输出: " + i);
    }
}

Implement the Runnable interface to create multi-threaded, anonymous inner classes combined with Lambda expressions to simplify the third method :

public static void main(String[] args) {
    
    
    // 1. 创建任务对象(匿名内部类的方式)
    // 2. 将任务对象交给线程对象(Thread)处理
    // 3. 启动线程
    new Thread(() -> {
    
    
        for (int i = 0; i < 5; i++) {
    
    
            System.out.println("子线程执行输出: " + i);
        }
    }).start();

    // 主线程执行的操作
    for (int i = 0; i < 5; i++) {
    
    
        System.out.println("主线程执行输出: " + i);
    }
}

The advantages and disadvantages of implementing the Runnable interface to create multiple threads :

Advantages: The thread task class only implements the interface, can continue to inherit the class and implement the interface, and has strong scalability.

Disadvantage: There is an extra layer of object packaging for programming. If the thread has an execution result, the returned result cannot be obtained.

Method 3: Implement the Callable interface

There is a problem with the first two thread creation methods :

None of their rewritten run methods can return results directly.

It is not suitable for business scenarios that need to return thread execution results.

So how to solve this problem ?

JDK 5.0 provides a combination of Callable and FutureTask to achieve multi-threading.

The advantage of this way of implementing multithreading is that the results of thread execution can be obtained.

Multithreading implementation scheme three: use Callable and FutureTask interfaces to implement, and the implementation steps are as follows :

① Get the task object

  • Define the class to implement the Callable interface, rewrite the call method, and the call method encapsulates what we want to do, and the call method can return the result.
  • Give the Callable task object to FutureTask and encapsulate it into a thread task object.

② Hand over the thread task object to the thread object (Thread) for processing.

③ Call the start method of Thread to start the thread and execute the task

④ After the thread is executed, use the get method of FutureTask to obtain the result of task execution.

The role of using FutureTask packaging :

Function 1: Thread thread object constructor only accepts objects of type Runnable, and FutureTask implements the Runnable interface, which can be handed over to Thread for processing

Function 2: You can get the result of the thread execution by calling its get method after the thread execution is completed

FutureTask API

method name illustrate
FutureTask<>(Callable call) Encapsulate the Callable object into a FutureTask object.
get() throws Exception Get the result returned by the thread execution call method.

demo code

public class ThreadDemo4 {
    
    
    public static void main(String[] args) {
    
    
        // 3. 创建任务对象
        Callable<String> callable  = new MyCallable(5);

        // 4. 将任务对象包装成线程任务对象
        FutureTask<String> ft = new FutureTask<>(callable);

        // 5. 将线程任务对象交给线程对象(Thread)处理
        Thread t = new Thread(ft);

        // 6. 启动线程
        t.start();

        // 获取线程执行的结果, 会返回正常的结果和异常的结果
        try {
    
    
            String res = ft.get();
            System.out.println(res);
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }
    }
}

/**
    1. 定义类实现Callable接口
    泛型自定义返回值类型
 */
class MyCallable implements Callable<String> {
    
    
    private int n;
    public MyCallable(int n) {
    
    
        this.n = n;
    }
    /**
        2. 重新实现类call方法(任务方法)
     */
    @Override
    public String call() throws Exception {
    
    
        int sum = 0;
        for (int i = 1; i <= n ; i++) {
    
    
            sum += i;
        }
        return "子线程方法执行的结果是" + sum;
    }
}

Advantages and disadvantages of method three :

Advantages: The thread task class only implements the interface, can continue to inherit the class and implement the interface, and has strong scalability.

The result of thread execution can be obtained after the thread execution is completed.

Disadvantages: Coding will appear a little more complicated.

Summary: The comparison of the three methods is as follows

Way advantage shortcoming
Inherit the Thread class Programming is relatively simple, you can directly use the methods in the Thread class Poor scalability, can no longer inherit other classes, can not return the result of thread execution
Implement the Runnable interface It is highly extensible, and can inherit other classes while implementing this interface. Programming is relatively complicated, and the result of thread execution cannot be returned
Implement the Callable interface It is highly extensible, and can inherit other classes while implementing this interface. The result of thread execution can be obtained Programming is relatively complicated

Guess you like

Origin blog.csdn.net/m0_71485750/article/details/127653913