创建线程的几种方式
Thread
- 普通写法
Thread thread = new Thread() {
@Override
public void run() {
System.out.println("hello");
}
};
thread.start();
Thread类实现了Runnable接口,必须重写run方法.run方法并不是开启该线程,必须执行了start方法,才能运行该线程,运行即为运行run方法中的内容。
- lambda表达式写法
new Thread(() -> System.out.println("hello")).start();
- FutureTask
FutureTask<Integer> futureTask = new FutureTask(() -> 100);
new Thread(futureTask).start();
System.out.println(futureTask.get());
FutureTask是一个实现了RunnableFuture接口的类,它可以用来包装一个Callable或Runnable对象,作为一个异步任务来执行。FutureTask可以被提交给一个Executor来执行,并且可以查询任务的执行状态或取消任务的执行。
通过FutureTask,你可以在一个单独的线程中执行一个任务,并且在需要时获取任务的执行结果
ScheduledExecutorService(延迟任务)
ScheduledExecutorService是一个接口,它提供了一种调度任务在指定时间或以固定频率执行的方法。可以使用ScheduledExecutorService来创建一个线程池,并使用schedule()或scheduleAtFixedRate()等方法安排任务的执行。这对于需要按计划执行的周期性任务非常有用。
private final ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
/**
* 延时任务
* 参数1:任务
* 参数2:方法第一次执行的延迟时间
* 参数3:延迟单位
* 说明:延迟任务,只执行一次(不会再次执行),参数2为延迟时间
*/
@GetMapping("/x")
private void x() {
scheduledThreadPool.schedule(() -> System.out.println("hello"), 5, TimeUnit.SECONDS);
}
/**
* 循环任务,按照上一次任务的发起时间计算下一次任务的开始时间
* 参数1:任务
* 参数2:初始化完成后延迟多长时间执行第一次任务
* 参数3:任务时间间隔
* 参数4:单位
* 说明:如果上一个任务没有执行完毕,则需要等上一个任务执行完毕后立即执行,如果你的任务执行时间超过间隔时间,那么任务时间间隔参数将无效,任务会不停地循环执行,该方法不能严格保证任务按一定时间间隔执行。
*/
@GetMapping("/xx")
private void xx() {
scheduledThreadPool.scheduleAtFixedRate(() -> System.out.println("hello"), 0, 2, TimeUnit.SECONDS);
}
/**
* 循环任务,以上一次任务的结束时间计算下一次任务的开始时间
* 参数1:任务
* 参数2:初始化完成后延迟多长时间执行第一次任务
* 参数3:任务执行时间间隔
* 参数4:单位
* 说明:以上一次任务执行结束时间为准,加上任务时间间隔作为下一次任务开始时间,该方法可以严格按照时间间隔执行
*/
@GetMapping("/xxx")
private void xxx() {
scheduledThreadPool.scheduleWithFixedDelay(() -> System.out.println("hello"), 0, 2, TimeUnit.SECONDS);
}
CompletableFuture(异步任务)
CompletableFuture是一个用于处理异步任务的工具类,可以使用自定义线程池,如果使用指定线程池,默认情况下CompletableFuture会使用公共的ForkJoinPool.commonPool()线程池
详细参考
异步返回值需要等待任务执行完毕后才能获取返回结果,所以多个异步任务时一定要注意先调用完方法以后再操作返回对象,以免造成方法是同步执行的。
- 单任务执行
/**
* 创建一个不带返回值得任务(默认线程池)。
*/
CompletableFuture<Void> f1 = CompletableFuture.runAsync(new Runnable() {
@Override
public void run() {
//业务逻辑
}
});
/**
* 创建一个带返回值的任务(默认线程池)。
*/
CompletableFuture<String> f2 = CompletableFuture.supplyAsync(new Supplier<String>() {
@Override
public String get() {
//业务逻辑
return null;
}
});
- 多任务返回值
//创建线程池
ExecutorService executor = Executors.newFixedThreadPool(10);
// 任务1
CompletableFuture<Integer> f1 = CompletableFuture.supplyAsync(() -> 1, executor);
// 任务2
CompletableFuture<Integer> f2 = CompletableFuture.supplyAsync(() -> 2, executor);
// 任务3
CompletableFuture<Integer> f3 = CompletableFuture.supplyAsync(() -> 3, executor);
// 创建一个map用于接收三个任务的结果
Map<String, Integer> map = CompletableFuture.allOf(f1, f2, f3).thenApply(v ->
new HashMap<String, Integer>() {{
try {
put("task_1", f1.get());
put("task_2", f2.get());
put("task_3", f3.get());
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
}}).join();
ScheduledExecutorService与CompletableFuture差别
CompletableFuture还提供了一些其他方法,例如allOf()、anyOf()等,用于处理多个异步任务的结果。
综上所述,ScheduledExecutorService适用于调度和执行按计划执行的任务,而CompletableFuture适用于处理异步操作的结果。你可以根据具体的需求选择使用哪个并发工具。