1. oracle articles 中的例子
oracle 文章:分解和合并:Java 也擅长轻松的并行编程!
简单例子 by Julien Ponge:
import java.util.*;
import java.util.concurrent.*;
import static java.util.Arrays.asList;
public class Sums {
// Callable,有返回值
static class Sum implements Callable<Long> {
// 传入参数: from 和 to
private final long from;
private final long to;
// 从带参的构造器这里获得传入的参数:from 和 to
Sum(long from, long to) {
this.from = from;
this.to = to;
}
// 返回Long类型的自加结果
@Override
public Long call() {
long acc = 0;
// 从0开始的自加循环,从from计数到to
for (long i = from; i <= to; i++) {
acc = acc + i;
}
return acc;
}
}
public static void main(String[] args) throws Exception {
ExecutorService executor = Executors.newFixedThreadPool(2);
List <Future<Long>> results = executor.invokeAll(asList(
new Sum(0, 10), new Sum(100, 1_000), new Sum(10_000, 1_000_000)
));
executor.shutdown();
for (Future<Long> result : results) {
System.out.println(result.get());
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
2. 在 SpringBoot 中调用
作为新手使用,仿写简单类:
/**
* 文件下载工具类
* @author jok
* @date 2019/8/28 15:25
*/
public class DownloadUtils {
/**
* 下载文件
* Callable:可自定义返回值
* @author jok
* @date 2019/8/28 15:25
*/
public class DownloadFileCall implements Callable<String>
{
private final Integer fileId;
private final FileInfoService fileInfoService;
// 带参构造器为public,否则无法被外部访问到
// 从带参的构造器这里获得传入的参数:ID、Service 等
public DownloadFileCall(Integer fileId , FileInfoService fileInfoService) {
this.fileId = fileId ;
this.fileInfoService = fileInfoService;
}
// 可自定义返回值
@Override
public String call() {
// TO-DO your code
// pojo类FileInfo:放点简单的整数文件ID和文件名字符串
FileInfo fileInfo = this.fileInfoService.getInfoById(fileId);
System.out.println("fileId = " + fileId);
return fileInfo.toString();
}
}
/**
* 下载文件
* Runnable,无返回值
* @author jok
* @date 2019/9/17 23:30
*/
public class DownloadFileRun implements Runnable {
private final Integer fileId;
private final FileInfoService fileInfoService;
// 带参构造器为public,否则无法被外部访问到
// 从带参的构造器这里获得传入的参数:ID、Service 等
public DownloadFileRun(Integer fileId, FileInfoService fileInfoService) {
this.fileId = fileId;
this.fileInfoService = fileInfoService;
}
// 无返回值
@Override
public void run() {
// TO-DO your code
FileInfo fileInfo = this.fileInfoService.getInfoById(fileId);
System.out.println("fileId = " + fileId);
System.out.println(fileInfo.toString());
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
于是,在其他类中实例化带参数的 Callalbe / Runnable,并且运行里面的 call() / run():
// 实例化
DownloadUtils downloadUtils = new DownloadUtils();
// 传入参数 ID、Service
// 如果带参的构造器是private,这里就用不了
DownloadUtils.DownloadFileRun downloadFileRun
= downloadUtils.new DownloadFileRun(fileId, fileInfoService);
DownloadUtils.DownloadFileCall downloadFileCall
= downloadUtils.new DownloadFileCall(fileId, fileInfoService);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
// 接收Callable的返回值
String fileInfo = downloadFile.call(1, this.fileInfoService);
downloadFileRun.run(1, this.fileInfoService);
- 1
- 2
- 3
- 4
在SpringBoot中,上面的Runnable作为异步(定时)任务调用:
参考了:SpringBoot中并发定时任务的实现、动态定时任务的实现
/**
*ClassName: DynamicTimedTask
*Description: 定时任务、动态任务
*@author zhuanlan.zhihu.com/p/61526583
*@date 2019/4/5
*@version 1.0
**/
@Component(value = "dynamicTimedTask")
@Log4j2
public class DynamicTimedTask {
@Autowire
private final FileInfoService fileInfoService;
public DynamicTimedTask(FileInfoService fileInfoService) {
fileInfoService = this.fileInfoService;
}
/**
* 接受任务的返回结果
*/
private ScheduledFuture<?> future;
@Autowired
private ThreadPoolTaskScheduler threadPoolTaskScheduler;
/**
* 实例化一个线程池任务调度类,可以使用自定义的 ThreadPoolTaskScheduler
* @return org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler
*/
@Bean
public ThreadPoolTaskScheduler threadPoolTaskScheduler() {
ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
// 定义线程池数量
threadPoolTaskScheduler.setPoolSize(5);
// 给线程自定义一个名称
threadPoolTaskScheduler.setThreadNamePrefix("threadPoolTaskScheduler-");
// 调度器shutdown被调用时等待当前被调度的任务完成,默认为false
threadPoolTaskScheduler.setWaitForTasksToCompleteOnShutdown(false);
// 等待时长
threadPoolTaskScheduler.setAwaitTerminationSeconds(60);
return threadPoolTaskScheduler;
}
/**
* 开启定时任务:下载文件
* 间隔60秒
* @param fileId 文件信息ID
* @param fileInfoService 文件信息服务
* @author jok
* @date 2019/9/17 23:27
*/
@Async
public void startDownloadFile(Integer fileId, FileInfoService fileInfoService)
{
// 如果带参的构造器是private,这里就用不了
DownloadUtils downloadUtils = new DownloadUtils();
DownloadUtils.DownloadFileRun downloadFileRun
= downloadUtils.new DownloadFileRun(fileId, fileInfoService);
try {
// 时间间隔:60秒
String cron = "0/60 * * * * ?";
future = threadPoolTaskScheduler.schedule(
downloadFileRun, new CronTrigger(cron));
} catch (Exception e) {
log.error("定时任务启动过程失败:" + e.getMessage(), e);
}
}
/**
* 停止定时任务
* @author jok
* @date 2019/9/17 23:28
*/
@Async
public void stopDownloadFile()
{
if (future != null) {
try {
future.cancel(true);
// 不一定必须用shutdown,看具体情况
threadPoolTaskScheduler.shutdown();
} catch (Exception e) {
log.error("定时任务停止失败:" + e.getMessage(), e);
}
} else {
log.info("定时任务已经停止!!!");
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
在Controller中,开启/停止定时任务:
@Controller
@Log4j2
public class DownloadController {
@Autowired
FileInfoService fileInfoService;
/**
* 开启定时任务:下载文件
* @return org.springframework.web.servlet.ModelAndView
* @author jok
* @date 2019/9/17 22:15
*/
@GetMapping("/start")
public ModelAndView start() {
try {
log.info("开启定时下载 thread id :" + Thread.currentThread().getName());
// 同时调用
dynamicTimedTask.startDownloadFile(1, this.fileInfoService);
dynamicTimedTask.startDownloadFile(2, this.fileInfoService);
dynamicTimedTask.startDownloadFile(3, this.fileInfoService);
} catch (Exception e) {
log.error("定时下载任务过程错误:" + e.getMessage(), e);
}
return new ModelAndView("/downloading");
}
/**
* 停止定时任务
* @return org.springframework.web.servlet.ModelAndView
* @author jok
* @date 2019/9/17 22:15
*/
@GetMapping("/stop")
public ModelAndView stop() {
try {
log.info("停止定时下载 thread id :" + Thread.currentThread().getName());
dynamicTimedTask.stopDownloadFile();
} catch (Exception e) {
log.error("停止定时下载任务过程错误:" + e.getMessage(), e);
}
return new ModelAndView("/stop");
}
}
来源:oschina
链接:https://my.oschina.net/u/2963604/blog/4812860