使用实现多线程有四种方式:
继承 Thread 类;
实现 Runnable 接口;
使用 Callable 和 FutureTask 实现有返回值的多线程;
使用 ExecutorService 和 Executors 工具类实现线程池(如果需要线程的返回值,需要在线程中实现 Callable
和 Future 接口)
Thread 类本质上是实现了 Runnable 接口的一个实例,代表一个线程的实例。启动线程的唯一方法就是通过
Thread 类的 start() 实例方法,start() 方法是一个 native 方法,它将启动一个新线程,并执行 run() 方法。
继承 Thread 类的优点:简单,且只需要实现父类的 run 方法即可( start 方法中含有 run 方法,会创建一个新的
线程,而 run 是执行当前线程)。
继承 Thread 类的缺点:Java 的单继承,如果对象已经继承了其他的类则不能使用该方法,且不能获取线程的返回
值。
package com.multithreading;
public class ThreadDemo {
public static void main(String[] args) {
MyThread1 myThread1 = new MyThread1();
MyThread1 myThread2 = new MyThread1();
myThread1.start();
myThread2.start();
}
}
class MyThread1 extends Thread {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
# 程序输出
Thread-1
Thread-0
实现 Runnable 接口优点:简单,实现 Runnable 接口必须实现 run 方法。
实现 Runnable 接口缺点:创建一个线程就必须创建一个 Runnable 的实现类,且不能获取线程的返回值。
package com.multithreading;
public class RunnableDemo {
public static void main(String[] args) {
System.out.println(Thread.currentThread().getName());
Thread t1 = new Thread(new MyThread2());
t1.start();
}
}
class MyThread2 implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
# 程序输出
main
Thread-0
CallabTask 优点:可以获取多线程的返回值。
CallabTask 缺点:每个多线程都需要创建一个 Callable 的实现类。
package com.multithreading;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class CallableDemo {
public static void main(String[] args) {
FutureTask<String> futureTask = new FutureTask<>(new CallerTask());
new Thread(futureTask).start();
try {
String result = futureTask.get();
System.out.println(result);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
class CallerTask implements Callable<String> {
@Override
public String call() {
return Thread.currentThread().getName();
}
}
# 程序输出
Thread-0
线程池 ExecutorService 和工具类 Executors 优点:可以根据实际情况创建线程数量,且只需要创建一个线程池即
可,也能够通过 Callable 和 Future 接口得到线程的返回值,程序的执行时间与线程的数量紧密相关。
线程池 ExecutorService 和工具类 Executors 缺点:需要手动销毁该线程池(调用shutdown方法)。
package com.multithreading;
import java.util.concurrent.Callable;
public class MyTask implements Callable<String> {
private final int id;
public MyTask(int id) {
this.id = id;
}
@Override
public String call() {
return "result of TaskWithResult: " + id;
}
}
package com.multithreading;
import java.util.ArrayList;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class ExecutorServiceDemo {
static final int NUMBER = 10;
public static void main(String[] args) {
ExecutorService exec = Executors.newCachedThreadPool();
ArrayList<Future<String>> results = new ArrayList<>();
for (int i = 0; i < NUMBER; i++) {
results.add(exec.submit(new MyTask(i)));
}
exec.shutdown();
for (Future<String> future : results) {
try {
System.out.println(future.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
}
# 程序输出
result of TaskWithResult: 0
result of TaskWithResult: 1
result of TaskWithResult: 2
result of TaskWithResult: 3
result of TaskWithResult: 4
result of TaskWithResult: 5
result of TaskWithResult: 6
result of TaskWithResult: 7
result of TaskWithResult: 8
result of TaskWithResult: 9