创建线程的方式有几种
继承 Thread 类
这是最直接的一种方式,通过创建一个继承自 Thread 类的子类,并重写其 run() 方法来定义线程需要执行的任务。
实现步骤:
1. 定义一个类继承 Thread 类。
2. 重写 run() 方法,将线程要执行的逻辑代码放入其中。
3. 创建该子类的实例,即创建了线程对象。
4. 调用线程对象的 start() 方法来启动线程。
示例:
class MyThread extends Thread {
@Override
public void run() {
System.out.println("通过继承Thread类创建线程...");
}
}
// 启动线程
MyThread t = new MyThread();
t.start();
实现 Runnable 接口
这种方式下,线程的执行任务(Runnable)与线程的创建和管理(Thread)是分离的。
实现步骤:
1. 定义一个类实现 Runnable 接口。
2. 实现 run() 方法,这个方法是线程的执行体。
3. 创建 Runnable 实现类的实例。
4. 将该实例作为参数传递给 Thread 类的构造函数来创建线程对象。
5. 调用 Thread 对象的 start() 方法。
示例:
class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("通过实现Runnable接口创建线程...");
}
}
// 启动线程
MyRunnable myRunnable = new MyRunnable();
Thread t = new Thread(myRunnable);
t.start();
实现 Callable 接口(配合 FutureTask 或线程池)
从Java 1.5开始引入,这种方式是对 Runnable 的一个重要补充,主要用于需要获取线程执行结果或处理线程抛出异常的场景。
实现步骤:
1. 创建一个类实现 Callable<V> 接口,其中 V 是返回值的类型。
2. 实现 call() 方法,该方法有返回值,并且可以抛出异常。
3. 使用 FutureTask 类来包装 Callable 对象。
4. 将 FutureTask 对象作为参数传递给 Thread 构造函数并启动线程。
5. 通过 FutureTask 对象的 get() 方法获取线程执行的返回值(该方法会阻塞,直到任务完成)。
示例:
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
class MyCallable implements Callable<String> {
@Override
public String call() throws Exception {
Thread.sleep(1000);
return "线程执行完成";
}
}
// 启动线程并获取结果
MyCallable myCallable = new MyCallable();
FutureTask<String> futureTask = new FutureTask<>(myCallable);
Thread t = new Thread(futureTask);
t.start();
// 获取返回值
String result = futureTask.get(); // 阻塞等待
System.out.println(result);
使用线程池
在实际开发中,频繁地创建和销毁线程会带来很大的性能开销。因此,更推荐使用线程池来管理线程。线程池可以复用已创建的线程,控制并发线程的数量。
实现步骤:
1. 使用 Executors 工厂类创建所需类型的线程池(如 newFixedThreadPool, newCachedThreadPool 等)。
2. 创建实现了 Runnable 或 Callable 接口的任务。
3. 通过线程池的 submit() 或 execute() 方法提交任务。
4. 当不再需要线程池时,调用 shutdown() 方法关闭。
示例:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
// ... MyRunnable class from above ...
// 创建线程池并提交任务
ExecutorService executorService = Executors.newFixedThreadPool(5);
executorService.execute(new MyRunnable());
executorService.shutdown();