【问题标题】:I want to start a task periodically after every 1 second no matter whether previous task ends on not无论上一个任务是否结束,我都想每隔 1 秒定期启动一个任务
【发布时间】:2016-11-08 18:03:17
【问题描述】:

无论之前的任务是否结束,我都想每隔 1 秒定期运行一次任务。我尝试了下面的代码,但它没有工作它正在等待 完成上一个任务然后开始另一个任务。

public static void main(String[] args) throws Exception {
     ScheduledExecutorService scheduledPool = Executors.newScheduledThreadPool(5);
     scheduledPool.scheduleAtFixedRate(new Runnable(){
                 public void run(){
                     System.out.println(Thread.currentThread().getName() + "startTime : "+ new Date());
                    sleepForNSeconds(5);
                     System.out.println(Thread.currentThread().getName()  +"endTime : "+ new Date());
                 }
                 }, 0,1, TimeUnit.SECONDS);

 }

输出:

pool-1-thread-1startTime : Wed Jul 06 21:04:15 IST 2016
pool-1-thread-1endTime : Wed Jul 06 21:04:21 IST 2016
pool-1-thread-1startTime : Wed Jul 06 21:04:21 IST 2016
pool-1-thread-1endTime : Wed Jul 06 21:04:26 IST 2016
pool-1-thread-2startTime : Wed Jul 06 21:04:26 IST 2016

请建议我应该使用哪个 api 来实现这一点。我希望 startTime 应该每 1 秒打印一次,无论它是否完成。

如果 coreSize 为 5,那么当 5 个线程已经在工作时,如果需要,ScheduledExecutorService 可以创建多少个新线程?

注意:我也尝试了 Timer 类的 scheduleAtFixedRate api,但这也不能解决我的目的。

【问题讨论】:

    标签: java multithreading threadpool


    【解决方案1】:

    以下是我的方法。请建议是否有更好的方法。

    public static void main(String[] args) throws Exception {
         while(true){
             sleepForNSeconds(1);
             new Thread(new Test().new Mytask()).start();
         }
    
     }  
    
     class Mytask implements Runnable {
    
         public void run() {
             System.out.println(Thread.currentThread().getName()
                     + " startTime : " + new Date());
             sleepForNSeconds(5);
             System.out.println(Thread.currentThread().getName() + " endTime : "
                     + new Date());
         }
     } 
    

    输出:

    Thread-0 startTime : Wed Jul 06 21:41:47 IST 2016
    Thread-1 startTime : Wed Jul 06 21:41:48 IST 2016
    Thread-2 startTime : Wed Jul 06 21:41:49 IST 2016
    Thread-3 startTime : Wed Jul 06 21:41:50 IST 2016
    Thread-4 startTime : Wed Jul 06 21:41:51 IST 2016
    Thread-0 endTime : Wed Jul 06 21:41:53 IST 2016
    Thread-5 startTime : Wed Jul 06 21:41:53 IST 2016
    Thread-1 endTime : Wed Jul 06 21:41:54 IST 2016  
    

    【讨论】:

    • 创建和销毁线程的成本很高。使用线程池(例如ThreadPoolExecutor)来重用线程要好得多。如果您想每秒触发一个任务,并且如果每个任务平均需要 N 秒来执行,那么您将希望池中至少有 N 个线程。
    • 是的,你是对的,但在我的情况下,我不知道任务需要多长时间可能需要 1 秒到 15 分钟。在这种情况下保持核心尺寸 15*60 是否可取?
    • 900 个线程很多。那些必须每秒精确启动一次、不能中止并且完成时间变化很大的任务是什么?
    • 他们正在执行一些 cassandra 数据库操作(读/写)。并且延迟取决于加载到 db(或其他原因)上,如果加载了 db,则延迟很高。如果我每 60 秒运行一次该线程并且 taks 的时间最长为 15 分钟(尽管到目前为止我已经观察到 5 分钟的延迟,但我玩得很安全)那么保持核心大小 15 是否可以?
    【解决方案2】:

    使用scheduleAtFixedRate() 方法不是个好主意,就像docs 说的那样:

    如果此任务的任何执行时间超过其周期,则后续执行可能会延迟开始,但不会同时执行。

    您始终可以使用schedule() 方法并在开始时调用自己,也应该可以:

        ScheduledExecutorService scheduledPool = Executors.newScheduledThreadPool(5);
        scheduledPool.schedule(new Runnable(){
            public void run(){
                scheduledPool.schedule(this,1,TimeUnit.SECONDS);
                System.out.println(Thread.currentThread().getName() + "startTime : "+ new Date());
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()  +"endTime : "+ new Date());
            }
        },1, TimeUnit.SECONDS);
    }
    

    【讨论】:

    • 感谢您的回复。但是,如果睡眠时间为 10 秒且核心大小为 5,则这不会按预期工作。在我的情况下,我不知道任务需要多长时间,它可能需要 1 秒到 15 分钟。
    猜你喜欢
    • 2015-11-22
    • 1970-01-01
    • 2012-08-22
    • 2015-04-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-12
    • 2015-11-22
    相关资源
    最近更新 更多