Are there 1, 2, or 4 ways to implement multithreading?

picture.png

Get into the habit of writing together! This is the third day of my participation in the "Nuggets Daily New Plan · April Update Challenge", click to view the details of the event .

1. How are the documents on the Oracle official website written?

  • Method 1: Implement the Runnable interface
  • Method 2: Inherit the Thread class

Implement the Runnable interface

package threadcoreknowledge.createthreads;

/**
 * 描述: 用Runnable方式创建线程
 */
public class RunnableStyle implements Runnable{
    public static void main(String[] args) {
        Thread thread = new Thread(new RunnableStyle());
        thread.start();
    }
    public void run() {
        System.out.println("用Runnable方式创建线程");
    }
}
复制代码

Inherit from the Thread class

package threadcoreknowledge.createthreads;

/**
 * 描述:  用Thread方式实现线程
 */
public class ThreadStyle extends Thread{
    @Override
    public void run() {
        System.out.println("用Thread方式实现线程");
    }

    public static void main(String[] args) {
        new ThreadStyle().start(); 
    }
}
复制代码

2. Comparison of the two methods

Method 1 (implementing the Runnable interface) is better.

Disadvantages of method 2:

  • Considering the architecture of the code, the specific tasks to be executed (the contents of the run method) should be decoupled from Thread, and these two things should not be confused;
  • In terms of resource saving, the Thread class is inherited. Every time we want to create a new task, we can only create a new independent thread, and the consumption of a new independent thread is very large (because it needs to be created and destroyed);
  • Inheriting the Thread class, because Java does not support double inheritance, this class cannot inherit other classes, which greatly limits the scalability of the code.

The essential comparison of the two methods

  • Method 1: Finally call target.run();
    @Override
    public void run() {
        if (target != null) {
            target.run();
        }
    }
复制代码
  • Method 2: run() is completely rewritten

3. Question: What happens when two methods are used at the same time?

package threadcoreknowledge.createthreads;

/**
 * 描述  同时使用Runnable和Thread两种实现线程的方式
 */
public class BothRunnableThread {
    public static void main(String[] args) {
        new Thread(new Runnable() {  //传入Runnable对象
            @Override
            public void run() {
                System.out.println("我来自Runnable");
            }
        }){
            @Override				//重写run()方法
            public void run() {      	
                System.out.println("我来自Thread");
            }
        }.start();
    }
}
复制代码

Code execution result:

Consider from object-oriented thinking: because we rewrite the run() method, the three lines of run() method code of Thread no longer exist, and even if the Runnable object is passed in, it will no longer be executed.

4. Summary: the most accurate description

1. Usually we can be divided into two categories, Oracle also said the same

2. To be precise, there is only one way to create a thread, that is to construct the Thread class, and there are two ways to implement the execution unit of the thread

  • Method 1: Implement the run method of the Runnable interface and pass the Runnable instance to the Thread class;
  • Method 2: Override the run method of Thread (inheriting the Thread class).

5. Analysis of typical misconceptions

1. "Creating a thread in a thread pool is also a way to create a new thread"

package threadcoreknowledge.wrongways;

import javafx.concurrent.Task;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPools {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        for (int i = 0; i < 1000; i++) {
            executorService.submit(new Tasks() {
            });
        }
    }
}
class Tasks implements Runnable{

    @Override
    public void run() {
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName());
    }
}
复制代码

Code execution result:

public Thread newThread(Runnable r) {
	Thread t = new Thread(group, r,
		 namePrefix + threadNumber.getAndIncrement(),
						  0);
	if (t.isDaemon())
		t.setDaemon(false);
	if (t.getPriority() != Thread.NORM_PRIORITY)
		t.setPriority(Thread.NORM_PRIORITY);
	return t;
}
复制代码

Click on the source code and you can see that the thread pool essentially creates threads new Thread, so this is not a new way to create threads.

2. "Creating threads through Callable and FutureTask is also a way to create new threads"

The essence is to implement the Runnable interface and inherit the Thread class.

3. "No return value is to implement the runnable interface, and there is a return value to implement the callable interface, so callable is a new way to implement threads"

The essence is still implemented by implementing the Runnable interface and inheriting the Thread class.

4. Timer

package threadcoreknowledge.wrongways;

import java.util.Timer;
import java.util.TimerTask;

/**
 * 描述:      定时器创建线程
 */
public class DemoTimerTask {
    public static void main(String[] args) {
        Timer timer = new Timer();
        timer.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());
            }
        },1000,1000);
    }
}
复制代码

Code execution result:

5. Anonymous inner classes

package threadcoreknowledge.wrongways;

public class AnonymousInnerClassDemo {
    public static void main(String[] args) {
        new Thread(){
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());
            }
        }.start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());
            }
        }).start();
    }
}
复制代码

Code execution result:

Essentially the same.

6. Lambda expressions

package threadcoreknowledge.wrongways;

public class Lambda {
    public static void main(String[] args) {
        new Thread(()-> System.out.println(Thread.currentThread().getName())).start();
    }
}
复制代码

Code execution result:

Essentially the same.

6. Summary of typical misconceptions

The implementation of multi-threading is ever-changing in the code, but its essence remains the same. They use various packages, such as thread pools, timers, and the appearance of the package seems to be a way to realize the thread pool, but if we open the package and look through the source code to see the truth of his final realization, the essence is actually realization Runnable interface and inheritance Thread class.

7. Implementing Multithreading - Common Interview Questions

How many ways are there to implement threads? There are 5 ideas:

  1. From different perspectives, there will be different answers.
  2. The typical answer is two
  3. Let's look at the principle, the essence of both is the same
  4. Specifically, let’s talk about other ways
  5. in conclusion

Which way is better to implement Runnable interface or inherit from Thread class?

  1. From a code architecture perspective
  2. Loss of new thread
  3. Java does not support double inheritance

Guess you like

Origin juejin.im/post/7082722150091587621