在 Java 中,创建线程的方式有四种,分别是:继承 Thread 类、实现 Runnable 接口、使用 Callable 和 Future、使用线程池。以下是详细的解释和通俗的举例:
1. 继承 Thread 类
通过继承 Thread 类并重写 run() 方法来创建线程。
步骤:
- 创建一个
Thread类的子类,重写run()方法,定义线程执行的任务。 - 创建该子类的实例,并调用
start()方法启动线程。
代码示例:
class MyThread extends Thread {
@Override
public void run() {
System.out.println("Thread is running...");
}
}
public class ThreadExample {
public static void main(String[] args) {
MyThread thread = new MyThread(); // 创建线程对象
thread.start(); // 启动线程
}
}
解释:
MyThread类继承了Thread类,重写了run()方法,run()方法里是线程执行的任务。- 调用
start()方法启动线程,start()方法会调用run()方法,线程开始执行。
优点:
- 代码简单,适合不需要线程共享资源的场景。
缺点:
- 继承
Thread类无法再继承其他类,因为 Java 不支持多重继承。
2. 实现 Runnable 接口
创建一个实现了 Runnable 接口的类,并实现其 run() 方法。然后将该实例作为参数传递给 Thread 对象来创建线程。
步骤:
- 创建一个实现了
Runnable接口的类,并重写run()方法。 - 创建
Runnable实例,将其传递给Thread构造方法。 - 调用
start()启动线程。
代码示例:
class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("Runnable thread is running...");
}
}
public class RunnableExample {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable(); // 创建Runnable对象
Thread thread = new Thread(myRunnable); // 将Runnable对象传递给Thread
thread.start(); // 启动线程
}
}
解释:
MyRunnable类实现了Runnable接口,并重写了run()方法,定义线程执行的任务。Thread构造方法接收Runnable对象,调用start()启动线程。
优点:
- 适用于多个线程共享同一个
Runnable对象的场景。 - 可以避免
Thread类的单继承限制,Runnable实现类可以继承其他类。
缺点:
- 线程任务无法返回结果或抛出异常。
3. 使用 Callable 和 Future 接口
Callable 接口与 Runnable 接口类似,但它能够返回结果,并且可以抛出异常。通过 ExecutorService 来管理线程池,并提交 Callable 任务获取 Future 对象,以便在未来某个时刻获取任务的计算结果。
步骤:
- 创建实现
Callable接口的类,重写call()方法,定义线程任务,并返回结果。 - 使用
ExecutorService提交任务,返回一个Future对象,可以用来获取任务执行的结果。
代码示例:
import java.util.concurrent.*;
class MyCallable implements Callable<Integer> {
@Override
public Integer call() throws Exception {
System.out.println("Callable thread is running...");
return 42; // 返回结果
}
}
public class CallableExample {
public static void main(String[] args) throws Exception {
ExecutorService executor = Executors.newSingleThreadExecutor(); // 创建线程池
MyCallable myCallable = new MyCallable();
Future<Integer> future = executor.submit(myCallable); // 提交任务
// 获取任务的执行结果
Integer result = future.get();
System.out.println("Result: " + result);
executor.shutdown(); // 关闭线程池
}
}
解释:
MyCallable实现了Callable接口,重写了call()方法,返回结果42。- 使用
ExecutorService来创建线程池并提交Callable任务。 future.get()会阻塞并返回任务执行的结果。
优点:
- 适用于需要任务返回结果或需要处理异常的场景。
ExecutorService提供了线程池管理,线程复用,提高了效率。
缺点:
- 使用
Future.get()时会阻塞,直到任务完成并返回结果。
4. 使用线程池 (ExecutorService)
通过使用 ExecutorService 来创建和管理线程池,并提交任务。线程池允许线程复用,避免了频繁创建和销毁线程的开销。
步骤:
- 使用
ExecutorService创建线程池,通常使用Executors类来创建。 - 提交任务到线程池执行,可以提交
Runnable或Callable任务。
代码示例:
import java.util.concurrent.*;
class MyRunnableTask implements Runnable {
@Override
public void run() {
System.out.println("Task is running in thread pool...");
}
}
public class ExecutorServiceExample {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(2); // 创建线程池,最多2个线程
executor.submit(new MyRunnableTask()); // 提交任务
executor.submit(new MyRunnableTask()); // 提交另一个任务
executor.shutdown(); // 关闭线程池
}
}
解释:
- 使用
Executors.newFixedThreadPool(2)创建了一个最多包含两个线程的线程池。 - 提交多个
Runnable任务到线程池,线程池负责线程的创建和管理。 shutdown()方法用于关闭线程池。
优点:
- 可以复用线程,避免了每次创建新线程的开销。
- 线程池可以根据系统资源动态调整线程数量,适用于高并发场景。
缺点:
- 需要管理线程池的生命周期,避免线程池资源泄漏。
总结
- 继承
Thread类:直接继承并重写run()方法,适合简单场景,但无法继承其他类。 - 实现
Runnable接口:实现Runnable接口的类并重写run()方法,适合共享任务的场景。 - 使用
Callable和Future:Callable可以返回结果并抛出异常,适合需要结果的任务,通过Future获取任务结果。 - 使用线程池:通过
ExecutorService创建线程池,复用线程,提高性能,适合高并发场景。
在实际开发中,线程池是推荐的方式,因为它不仅可以有效管理线程,还能提高程序的性能和可扩展性。






![python学习——洛谷P2010 [NOIP2016 普及组] 回文日期 三种方法](https://i-blog.csdnimg.cn/direct/cd82fc6aae654f17973ecbef6365552a.png)











