首页   注册   登录
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX  ›  Java

ThreadPoolTaskScheduler 怎么用多线程去跑任务呢

  •  
  •   shayang888 · 347 天前 · 1843 次点击
    这是一个创建于 347 天前的主题,其中的信息可能已经有所发展或是发生改变。
    @Autowired
    private ThreadPoolTaskScheduler threadPoolTaskScheduler;
    
    private ScheduledFuture<?> future;
    
    @Bean
    public ThreadPoolTaskScheduler threadPoolTaskScheduler() {
    return new ThreadPoolTaskScheduler();
    }
    
    传任务的 id,然后开启对应的任务
    public void taskStartService(int id){
            try {
                Optional<Task> taskOptional = taskRepository.findById(id);
                if (taskOptional.isPresent()) {
                    future = threadPoolTaskScheduler.schedule(() -> {
                            System.out.println("task-" + id + ", " + Thread.currentThread().getName() + "-" + Thread.currentThread().getId());
                            threadMap.put(id, future);
                        }
                    }, new CronTrigger(taskOptional.get().getTaskTime()));
        }
    

    然后我启动了 2 个任务,打印出来确实 2 个任务都在运行,但是为什么线程打印出来只有 1 个线程在跑呢

    task-1, threadPoolTaskScheduler-1-54
    task-2, threadPoolTaskScheduler-1-54
    

    实在是不会了,请大佬给点提示

    第 1 条附言  ·  347 天前

    我把线程的问题已经解决了,设置了poolsize,但是为什么我打印future得到的结果是一样的?而且在stopService里cancel方法并没有按我传递的任务id来停止对应的任务

    @Bean
        public ThreadPoolTaskScheduler threadPoolTaskScheduler() {
            threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
            threadPoolTaskScheduler.setPoolSize(10);
            threadPoolTaskScheduler.setWaitForTasksToCompleteOnShutdown(true);
            return threadPoolTaskScheduler;
        }
    public void taskStartService(int id){
                Optional<Task> taskOptional = taskRepository.findById(id);
                if (taskOptional.isPresent()) {
                    future = threadPoolTaskScheduler.schedule(() -> {
                        System.out.println("task-" + id + ", " + Thread.currentThread().getName() + "-" + Thread.currentThread().getId() + ", " + future);
                    }, new CronTrigger(taskOptional.get().getTaskTime()));
        }
    public void taskStopService(int id){
            if (taskRepository.findById(id).isPresent()) {
                if (future != null) {
                    future.cancel(true);
                }
        }
    
    31 回复  |  直到 2018-12-28 18:27:27 +08:00
        1
    wccc   347 天前   ♥ 1
    @Bean(destroyMethod = "shutdown")
    public ThreadPoolTaskScheduler scheduledThreadPool() {
    ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
    scheduler.setThreadNamePrefix("scheduled-thread-");
    scheduler.setPoolSize(10);
    //等待任务完成后关闭
    scheduler.setWaitForTasksToCompleteOnShutdown(true);
    //最多等待 60s
    scheduler.setAwaitTerminationSeconds(60);
    scheduler.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
    scheduler.initialize();
    return scheduler;
    }
    定义一个线程池
    默认实现只有一个线程的线程池
        2
    shayang888   347 天前
    @wccc
    你好,谢谢大佬,多个线程执行的问题我已经解决了,不过很奇怪为什么我在停止一个任务的时候 发现都停止了,然后我把 future 打印出来 发现是一摸一样的两个 task,这是怎么回事呢
    ```
    task-2, threadPoolTaskScheduler-1-53, DelegatingErrorHandlingRunnable for com.apitest.service.TaskService$$Lambda$1086/[email protected]
    task-1, threadPoolTaskScheduler-2-78, DelegatingErrorHandlingRunnable for com.apitest.service.TaskService$$Lambda$1086/[email protected]
    ```
    这是我启动的两个任务,我在 startService 里打印了这两个 future 为什么这个值是一样的?,这样的话 我如果想停止某个任务,让另一个任务不受影响继续运行该怎么办了
        3
    wccc   347 天前   ♥ 1
    建议打印 task 中执行日志
        4
    shayang888   347 天前
    @wccc
    future = threadPoolTaskScheduler.schedule(() -> {
    System.out.println("task-" + id + ", " + Thread.currentThread().getName() + "-" + Thread.currentThread().getId() + ", " + future);
    }, new CronTrigger(taskOptional.get().getTaskTime()));
    就是这样的,我打印 future 就得到的是一样的,这样我在调用 future.cancel()的时候 整个就停掉了,可是我只想停止单个的
        5
    wccc   347 天前
    不了解 ThreadPoolTaskScheduler 用于定时任务多线程的
    多线程 线程池通常不用这个
        6
    shayang888   347 天前
    @wccc 确实 我现在就是需要创建不同 cron 的任务来独自运行 或者你有比较好的办法吗
        7
    wccc   347 天前
    mq 延时消息
        8
    kkjinping   347 天前
    默认 private volatile int poolSize = 1;
        9
    kkjinping   347 天前
    需要手动调用 setPoolSize(int size)
        10
    kkjinping   347 天前   ♥ 1
    @shayang888 feature 会不会是因为并发导致的,打印出来的都是最后一个。
        11
    kkjinping   347 天前   ♥ 1
    @shayang888 threadMap.put(id, future);放到 lambda 外面可以吗
        12
    kkjinping   347 天前   ♥ 1
    @shayang888 private ScheduledFuture<?> future; 改成方法内局部变量应该也行
        13
    shayang888   347 天前
    @kkjinping 哇 谢谢大佬的回复 你有用过这个来做定时任务吗
        14
    shayang888   347 天前
    @kkjinping 放在局部里不行的 我这后面还有个 stopTaskService(int id) 是用来指定任务的停止的, 不过没按照我的需求生效我不知道为什么
    public void taskStopService(int id){
    if (taskRepository.findById(id).isPresent()) {
    if (future != null) {
    future.cancel(true);
    }
    }
        15
    DsuineGP   346 天前
    @shayang888 调用 future.cancel 只是向执行任务的线程发送中断指令,具体怎么响应这个指令需要在执行任务的线程中检测并作出相应的处理
        16
    kkjinping   346 天前
    @shayang888 threadMap.put(id, future); 你不是有这个吗,id 和 future 映射,那你关闭的时候就可以从 map 中拿到 future 了。所以可以把 future 放到局部变量。threadMap 是实例变量。
        17
    shayang888   346 天前
    @kkjinping 我这么做了 可是并没有用 拿到的 future 在 map 里显示出来是一摸一样的 future.cancel 就全给取消了
    {1=DelegatingErrorHandlingRunnable for com.apitest.service.TaskService$$Lambda$1106/[email protected], 2=DelegatingErrorHandlingRunnable for com.apitest.service.TaskService$$Lambda$1106/[email protected]}
    你看,future 的值是一摸一样的
        18
    kkjinping   346 天前
    @shayang888 你有改成局部变量吗,future。要两部结合起来。future 放到局部变量。threadMap 是实例变量。
        19
    kkjinping   346 天前
    @shayang888 threadMap.put(id, future);还要放到 lambda 外面
        20
    kkjinping   346 天前
    Optional<Task> taskOptional = taskRepository.findById(id);
    if (taskOptional.isPresent()) {
    future = threadPoolTaskScheduler.schedule(() -> {
    System.out.println("task-" + id + ", " + Thread.currentThread().getName() + "-" + Thread.currentThread().getId());

    }
    }, new CronTrigger(taskOptional.get().getTaskTime()));

    threadMap.put(id, future);
    }
        21
    kkjinping   346 天前
    Optional<Task> taskOptional = taskRepository.findById(id);
    if (taskOptional.isPresent()) {
    ScheduledFuture future = threadPoolTaskScheduler.schedule(() -> {
    System.out.println("task-" + id + ", " + Thread.currentThread().getName() + "-" + Thread.currentThread().getId());

    }
    }, new CronTrigger(taskOptional.get().getTaskTime()));

    threadMap.put(id, future);
    }
        22
    shayang888   346 天前
    @kkjinping 对呀 我代码就是这样的 map 是全局的 future 是局部的 可是得到的 future 都是一样的 所以在执行 stopTaskService 的时候,future.cancel()就会把所有的任务都取消了
    threadMap.get(id).cancel()
        23
    kkjinping   346 天前   ♥ 1
    @shayang888

    @Resource
    private ThreadPoolTaskScheduler threadPoolTaskScheduler;

    private Map<Integer, Future> futureMap = new HashMap<>(16);

    @Bean
    public ThreadPoolTaskScheduler threadPoolTaskScheduler(){
    ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
    threadPoolTaskScheduler.setPoolSize(10);
    return threadPoolTaskScheduler;
    }

    public void start(int id){
    Calendar calendar = Calendar.getInstance();
    calendar.add(Calendar.SECOND,5);
    ScheduledFuture future = threadPoolTaskScheduler.schedule(() -> {
    System.out.println(id + " " + Thread.currentThread().getName());
    }, calendar.getTime());
    futureMap.put(id,future);
    }

    public void stop(int id){
    Future future = futureMap.get(id);
    if(future!=null){
    future.cancel(true);
    }
    }


    我试了下没有问题,关闭不壶关全部的
        24
    shayang888   346 天前
    @kkjinping 谢谢 按你说的弄好了 不过我很想知道为什么两个 future 的值是一样的 能告诉下吗 或者有相关文档吗 google 了一圈也没找到
        25
    kkjinping   346 天前   ♥ 1
    @shayang888 你可以发下代码
        26
    shayang888   346 天前
    @kkjinping 代码跟你的一样 我就是在 stop 方法里 把 futureMap 打印了一下 发现每个 value 都是一样的 你没发现吗
        27
    kkjinping   346 天前
    @shayang888 我打印发现不一样呀
        28
    shayang888   346 天前
    @kkjinping 大佬 我的意思是 比如执行了 2 个 task 即传了两个不同的 id 在 start 方法里 然后在 start 方法里打印出 future 此时 1 的 value 和 2 的 value 是一样的
        29
    kkjinping   346 天前
    @shayang888 是按照我发的写的吗。我打印了不一样啊。
        30
    shayang888   346 天前
    @kkjinping 大佬方便加个 qq 吗 请教你下
        31
    kkjinping   346 天前
    @shayang888 2290968582
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   1023 人在线   最高记录 5043   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.3 · 33ms · UTC 18:51 · PVG 02:51 · LAX 10:51 · JFK 13:51
    ♥ Do have faith in what you're doing.