1. The main ways to implement multithreading:
One is to inherit the Thread class
An implementation of Runnable interface
2. The difference between inheriting the Thread class and implementing the Runnable interface:
- Since Java is a single inheritance method, you cannot inherit the Thread class if the thread class already inherits other classes, but you can use the way you implement the Runnable interface instead
- The run method of the Thread class cannot be shared, for example, Thread A cannot treat Thread B's run method as its own unit of execution, while Runnable can be easily implemented because multiple instances can be constructed from the same Runnable, which is generally understood to be Thread's task
- In terms of responsibilities, the Thread class is primarily responsible for the thread's own related responsibilities and controls, while Runnable is primarily responsible for the execution unit of thread logic
3. All ways threads implement
- Inherit Thread Class
- Implement Runnable Interface
- Implement the Callable interface and wrap it with FutureTask
- Use anonymous internal classes
- Using Lambda expressions
- Use thread pool
- Use timer
3.1, Inherit Thread Class
public class Thread1 extends Thread { @Override public void run() { System.out.println("inherit Thread mode"); } public static void main(String[] args) { Thread1 thread = new Thread1(); thread.start(); } }
3.2. Implementing Runnable Interface
public class Thread2 implements Runnable { @Override public void run() { System.out.println("Realization Runnable Interface mode"); } public static void main(String[] args) { Runnable runnable = new Thread2(); Thread thread2 = new Thread(runnable); thread2.start(); } }
3.3. Implement Callable interface and wrap it with FutureTask
public class Thread3 implements Callable<String> { @Override public String call() throws Exception { Thread.sleep(5000); return "Realization Callable And through FutureTask Packaged with return value"; } public static void main(String[] args) throws ExecutionException, InterruptedException { Thread3 thread3 = new Thread3(); FutureTask futureTask = new FutureTask(thread3); Thread thread = new Thread(futureTask); thread.start(); System.out.println("Thread has started"); // Synchronize to get returned results String result = (String) futureTask.get(); System.out.println(result); } }
3.4, Anonymous Internal Class
Anonymous internal classes also have a variety of variations, all three of which can be implicitly instantiated using anonymous internal classes.
public class Demo{ public static void main(String[] args) throws Exception { //Mode 1: Thread Anonymous Internal Class new Thread(){ @Override public void run() { // TODO Auto-generated method stub } }.start(); //Mode 2: Runnable Anonymous Internal Class new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub } }).start(); ... } }
The advantage of anonymous internal classes is ease of use, no extra classes need to be defined, and the disadvantage is poor code readability.
3.5, Lambda expression
public class Demo{ public static void main(String[] args) throws Exception { new Thread(() -> System.out.println("running") ).start() ; ... } }
Runnable is decorated with the @FunctionalInterface annotation, and there is only one method in the interface
3.6, Thread Pool
public class DemoThreadTask implements Runnable{ @Override public void run() { // TODO Auto-generated method stub System.out.println("running"); } public static void main(String[] args) { DemoThreadTask task = new DemoThreadTask(); ExecutorService ex = Executors.newCachedThreadPool(); ex.execute(task); } }
3.7, Timer
public class DemoTimmerTask { public static void main(String[] args) throws Exception { Timer timer = new Timer(); timer.scheduleAtFixedRate((new TimerTask() { @Override public void run() { System.out.println("Task Execution"); } }), 2000, 1000); } }
TimerTask implements the Runnable interface and Timer has a TimerThread inside that inherits from Thread.