创建线程的四种方式和区别
1. 继承 Thread 类并重写run方法
- 缺点:Java不支持多继承,继承Thread类后就不能继承其他类了;多个线程之间不能共享线程类的实例变量。没有返回值。
2. 实现 Runnable 接口
- 优点:还可以继承其他类; 多个线程共享同一个target对象,所以适合多个相同线程来处理同一个份资源的情况,从而可以将CPU、代码和数据分开,形成清晰的模型,体现了面向对象的思想。
- 缺点:没有返回值。
3. 实现 Callable 接口
- 优点:还可以继承其他类; 多个线程共享同一个target对象,所以适合多个相同线程来处理同一个份资源的情况,从而可以将CPU、代码和数据分开,形成清晰的模型,体现了面向对象的思想; FutureTask 配合可以用来获取异步执行的结果。
- 返回的是一个 Future,通过它的 isDone 方法可以判断任务是否完成,如果任务已完成,那么可以通过它的get方法获取返回结果。也可以使用 FutureTask,因为Future是一个接口,无法直接用来创建对象进行使用,而FutureTask是一个实现类,它实现了 RunnableFuture 接口,这个接口继承了Runnable接口和Future接口,所以它既可以作为Runnable被线程执行,也可以作为Future得到Callable的返回值。
Callable和Runnable的区别:Runnable接口不会返回结果和抛出异常,Callable接口可以返回结果和抛出异常。
import java.util.concurrent.*;
public class fz {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService executor = Executors.newCachedThreadPool();
Task task = new Task();
// Future<Integer> res1 = executor.submit(task);
// executor.shutdown();
FutureTask<Integer> res2 = new FutureTask<>(task);
executor.submit(res2);
executor.shutdown();
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
System.out.println("主线程在执行任务");
try {
System.out.println("task运行结果" + res2.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
System.out.println("所有任务执行完毕");
}
}
class Task implements Callable<Integer> {
@Override
public Integer call() throws Exception {
System.out.println("子线程在进行计算");
Thread.sleep(3000);
int sum = 0;
for (int i = 0; i < 100; i++)
sum += i;
return sum;
}
}
4. 线程池的方式:Java中提供了一个Executors的类,通过它可以直接帮我们创建常用的线程池,比如:
Executors.newSingleThreadExecutor()
Executors.newFixedThreadPool()
Executors.newCachedThreadPool()
Executors.newScheduledThreadPool()
5. 手写创建线程的四种方式
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import java.util.concurrent.*; //现场手写可以只写这一个
public class MyThread {
//方法一:继承 Thread
public static class MyThread1 extends Thread {
@Override
public void run() {
//...
}
}
//方法二:实现 Runnable
public static class MyThread2 implements Runnable {
@Override
public void run() {
//...
}
}
//方法三:实现 Callable
public static class MyThread3 implements Callable<Integer> {
@Override
public Integer call() throws Exception {
return 123;
}
}
public static void main(String[] args) {
MyThread1 m1 = new MyThread1();
m1.start();
MyThread2 m2 = new MyThread2();
Thread t2 = new Thread(m2);
t2.start();
MyThread3 m3 = new MyThread3();
FutureTask<Integer> ft = new FutureTask<>(m3);
Thread t3 = new Thread(ft);
t3.start();
//方法四:线程池
ExecutorService e = Executors.newCachedThreadPool();
//lambda表达式
e.execute(() -> {
//...
});
e.shutdown();
e.execute(new Runnable() {
@Override
public void run() {
//...
}
});
}
}