网站首页 > 文章精选 正文
创建线程的五种方式
- 继承Thread类
- 实现Runnable接口
- 使用Callable和Future
- 使用Lambda表达式
- 使用线程池
继承Thread类创建线程
继承 Thread 类创建线程的步骤如下:
- 创建一个继承 Thread 类的子类。
- 重写 Thread 类的 run() 方法。
- 在 run() 方法中编写线程要执行的任务。
- 创建 Thread 子类的对象。
- 调用 Thread 子类对象的 start() 方法来启动线程。
以下是一个继承 Thread 类创建线程的示例:
public class MyThread extends Thread {
@Override
public void run() {
// 在 run() 方法中编写线程要执行的任务。
System.out.println("Hello, world!");
}
}
要启动 MyThread 线程,可以使用以下代码:
MyThread myThread = new MyThread();
myThread.start();
当 MyThread 线程启动后,它将执行 run() 方法中的代码,并在控制台上输出 "Hello, world!"。
实现Runnable接口
实现 Runnable 接口创建线程的步骤如下:
- 创建一个实现 Runnable 接口的类。
- 在 Runnable 接口的 run() 方法中编写线程要执行的任务。
- 创建 Runnable 接口的实现类的对象。
- 将 Runnable 接口的实现类的对象传递给 Thread 类的构造方法来创建 Thread 对象。
- 调用 Thread 对象的 start() 方法来启动线程。
以下是一个实现 Runnable 接口创建线程的示例:
public class MyRunnable implements Runnable {
@Override
public void run() {
// 在 run() 方法中编写线程要执行的任务。
System.out.println("Hello, world!");
}
}
要启动 MyRunnable 线程,可以使用以下代码:
Thread myThread = new Thread(new MyRunnable());
myThread.start();
当 MyRunnable 线程启动后,它将执行 run() 方法中的代码,并在控制台上输出 "Hello, world!"。
使用Callable和Future
Callable 和 Future 接口用于异步执行任务。Callable 接口用于创建可以返回结果的任务,Future 接口用于获取任务的结果。
Callable 接口的实现类必须实现 call() 方法,call() 方法用于执行任务并返回结果。Future 接口的实现类必须实现 get() 方法,get() 方法用于获取任务的结果。
Callable 和 Future 接口通常用于与线程池一起使用。线程池可以用于管理多个线程,并可以将任务提交给线程池以执行。当任务执行完成后,线程池会返回 Future 对象,Future 对象可以用于获取任务的结果。
以下是一个使用 Callable 和 Future 接口的示例:
ExecutorService executorService = Executors.newFixedThreadPool(10);
// 创建 Callable 对象
Callable<Integer> callable = new Callable<Integer>() {
@Override
public Integer call() throws Exception {
// 执行任务
System.out.println("任务正在执行...");
Thread.sleep(1000);
return 100;
}
};
// 将任务提交给线程池
Future<Integer> future = executorService.submit(callable);
// 获取任务的结果
try {
Integer result = future.get();
System.out.println("任务执行完成,结果为:" + result);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
// 关闭线程池
executorService.shutdown();
当程序执行完毕后,控制台将输出以下内容:
任务正在执行...
任务执行完成,结果为:100
当然我们可以不用线程池来实现:
Callable<Integer> callable = new Callable<Integer>() {
public Integer call() throws Exception {
// 线程的执行逻辑
System.out.println("线程执行逻辑");
return 100;
}
};
FutureTask<Integer> futureTask = new FutureTask<>(callable);
//因为future也是实现了runnable接口的
Thread thread = new Thread(futureTask);
thread.start();
try {
Integer result = futureTask.get();
System.out.println("任务执行完成,结果为:" + result);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
Callable 接口提供了一个 call() 方法,用于执行任务并返回结果。FutureTask 类是 Future 和 Runnable 接口的实现类,它保存着 call() 方法和实现了 Runnable 的 run() 方法,还有线程的状态和返回值变量,在调用run()方法的时候会执行call()。
当调用 FutureTask.get() 方法时,FutureTask 会先判断线程是否执行完成。如果线程已经执行完成,则 FutureTask 会返回线程的返回值。如果线程还没有执行完成,则 FutureTask 会调用 park() 方法使当前线程阻塞,直到线程执行完成后被唤醒。
FutureTask简化实现如下,源码是比这个要负责的。
public class FutureTask<V> implements RunnableFuture<V> {
// 任务是否已经执行完成
private volatile boolean done;
// 任务的返回值
private volatile V result;
// 构造函数
public FutureTask(Callable<V> callable) {
this.callable = callable;
}
public FutureTask(Runnable runnable, V result) {
this.runnable = runnable;
this.result = result;
}
@Override
public void run() { // 任务的执行方法
if (runnable != null) { // 执行Runnable任务
runnable.run();
} else { // 执行Callable任务
try {
result = callable.call();
} catch (Exception e) { // 捕获异常
setException(e);
}
}
done = true; // 任务执行完成
unparkSuccessor(); // 唤醒线程
}
@Override
public boolean isDone() { // 判断任务是否已经执行完成
return done;
}
@Override
public V get() throws InterruptedException, ExecutionException { // 获取任务的返回值
if (done) { // 任务已经执行完成
return result;
}
park(); // 阻塞当前线程
return result; // 获取任务的返回值
}
@Override
public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { // 获取任务的返回值,带有超时时间
if (done) { // 任务已经执行完成
return result;
}
park(unit.toNanos(timeout)); // 阻塞当前线程,指定超时时间
return result; // 获取任务的返回值
}
private void park() { // 阻塞当前线程
if (Thread.currentThread() != this) { // 当前线程不是FutureTask的执行线程
LockSupport.park(this); // 调用park()方法使当前线程阻塞
}
}
private void unparkSuccessor() { // 唤醒线程
if (successor != null) { // 后继线程不为null
LockSupport.unpark(successor); // 唤醒线程
}
}
}
使用Executor框架
使用Executor框架可以更方便地管理和调度线程。通过使用ExecutorService接口的实现类(如ThreadPoolExecutor),可以创建线程池,并将任务提交给线程池来执行。让我们看看下面的示例:
ExecutorService executor = Executors.newFixedThreadPool(5);
// 创建Runnable对象
Runnable runnable = () -> {
// 线程的执行逻辑
System.out.println("线程执行逻辑");
};
// 提交任务给线程池
executor.submit(runnable);
// 关闭线程池
executor.shutdown();
使用Lambda表达式
在Java 8及更高版本中,可以使用Lambda表达式来简化线程的创建和执行。通过将逻辑代码封装在Lambda表达式中,你可以更加简洁地创建线程。让我们看看下面的示例:
Thread thread = new Thread(() -> {
// 线程的执行逻辑
System.out.println("线程执行逻辑");
});
// 启动线程
thread.start();
总结
继承 Thread 类是最简单的创建线程的方式,但是需要重写 Thread 类的 run() 方法,并在 run() 方法中编写线程要执行的任务。
实现 Runnable 接口是创建线程的另一种方式,比继承 Thread 类更灵活,可以将线程要执行的任务封装在 Runnable 对象中,然后将 Runnable 对象传递给 Thread 类的构造方法,Thread 类会自动执行 Runnable 对象的 run() 方法。
Callable 接口和 Future 接口用于创建可以返回结果的线程。Callable 接口的实现类必须实现 call() 方法,call() 方法用于执行任务并返回结果。Future 接口用于获取任务的结果。
创建线程方法,说几种都可以,按照jdk源码注释上有写是两种,是继承Thread和实现Runnable。说一种也行,因为最后都是通过thread.start()来创建线程,等待cpu调度最后执行run()方法。其他的那几种到最后也就是上边两种方式的实现而已。
- 上一篇: 创建线程的 8 种方法
- 下一篇: RocketMQ中的线程池是如何创建的?
猜你喜欢
- 2025-01-02 Socket与TCP协议,利用python打造一个多人聊天室
- 2025-01-02 探讨C语言系统编程中线程的原理以及实现
- 2025-01-02 ffmpeg播放器实现详解 - 创建线程
- 2025-01-02 互联网面试-Java中如何去创建一个线程池?
- 2025-01-02 一篇详解内核监控进程与线程创建
- 2025-01-02 Python多线程,线程与进程的区别,线程模块及线程的两种创建方式
- 2025-01-02 正确使用线程池的姿势,你在工作中不要只会使用默认的方式创建
- 2025-01-02 Java线程池的正确创建方式
- 2025-01-02 [编程基础] C++多线程入门1-创建线程的三种不同方式
- 2025-01-02 Qt多线程创建
- 最近发表
- 标签列表
-
- newcoder (56)
- 字符串的长度是指 (45)
- drawcontours()参数说明 (60)
- unsignedshortint (59)
- postman并发请求 (47)
- python列表删除 (50)
- 左程云什么水平 (56)
- 计算机网络的拓扑结构是指() (45)
- 稳压管的稳压区是工作在什么区 (45)
- 编程题 (64)
- postgresql默认端口 (66)
- 数据库的概念模型独立于 (48)
- 产生系统死锁的原因可能是由于 (51)
- 数据库中只存放视图的 (62)
- 在vi中退出不保存的命令是 (53)
- 哪个命令可以将普通用户转换成超级用户 (49)
- noscript标签的作用 (48)
- 联合利华网申 (49)
- swagger和postman (46)
- 结构化程序设计主要强调 (53)
- 172.1 (57)
- apipostwebsocket (47)
- 唯品会后台 (61)
- 简历助手 (56)
- offshow (61)