繁体   English   中英

Java中Thread.sleep()的替代方法

[英]Alternative for Thread.sleep() in java

我在我的应用程序中使用spring ThreadPoolTaskExecutor 仅在星期五午夜才需要调用我的一种方法。 在服务器启动时调用该方法。 所以我以以下方式使用Thread.sleep()

Calendar today = Calendar.getInstance();
int dayOfWeek = today.get(Calendar.DAY_OF_WEEK);
int daysUntilNextFriday = Calendar.FRIDAY - dayOfWeek;
if(daysUntilNextFriday < 0){
    daysUntilNextFriday = daysUntilNextFriday + 7;
}       

Calendar c = Calendar.getInstance();

c.add(Calendar.DAY_OF_YEAR, daysUntilNextFriday);
c.set(Calendar.HOUR_OF_DAY, 0); 
c.set(Calendar.MINUTE, 0);
c.set(Calendar.SECOND, 0);
Date d1 = c.getTime();

long diffTime = d1.getTime() - new Date().getTime();

Thread.sleep(diffTime);

在某些情况下,它可能还要等待1天以上。 有没有比使用Thread.sleep()更好的方法了? 我已经看到在某些地方使用Thread.sleep()可能会导致性能问题。 就我而言,有没有其他选择可以提高性能?

最初,我们使用ThreadPoolTask​​Executor安排了近50个服务。 某些服务无法正常启动。过去1个月我们找不到确切的问题。因此,我们想尝试执行器

请参考此Spring Scheduler正在意外停止并再次启动

您在评论中说您正在使用Spring。 因此,您可以使用cron表达式。 有关如何使用Scheduler更多详细信息,请参见34.任务执行和调度

@Scheduled(cron="0 0 1 ? * FRI *")
public void doSomething() {
    // do stuff
}

这将使其在每周一的凌晨1点运行。 您可以使用Cron Maker生成表达式。

在您的Configuration类中,您必须启用“通过”计划。

@Configuration
@EnableAsync
@EnableScheduling
public class AppConfig {
}

您可以使用ScheduledExecutorService安排在一定时间后进行的工作。

ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
        scheduler.schedule(() -> {
            /*
             * define work to be done inside this lambda
             */
        }, diffTime, TimeUnit.MILLISECONDS);

注意:如果您希望工作在每个星期五的午夜(因此不仅仅是这个星期五)进行,则可以将schedule命令修改为以设定的时间间隔进行:

scheduler.scheduleAtFixedRate(() -> {
    /*
     * define work to be done inside this lambda
     */
    }, diffTime, Duration.ofDays(7).toMillis(), TimeUnit.MILLISECONDS);

使用ScheduledExecutorService

private static final ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);

如果您不担心准确性 (例如照顾夏令时变更):

您可以估算出固定的周期性:

7 * 24 * 60 * 60 * 1000 = 604800000(以毫秒为单位的一周)

然后,您可以像这样调用执行程序:

Runnable task = <your task extending Runnable>    
long difftime = <time to next friday>;
long week = 7 * 24 * 60 * 60 * 1000;

executor.scheduleAtFixedRate(task, difftime, week, TimeUnit.MILLISECONDS);

这将使执行程序首先等待difftime-delay,然后以指定的周期执行任务。

如果你担心的正确性 :然后改为调用:

executor.schedule(task, difftime, TimeUnit.MILLISECONDS);

只会执行一次任务。 在您的任务中-调用一个方法,该方法将使用新计算的difftime重新计划任务以进行下一次执行。

根据其他用户的建议,使用ThreadPoolTaskScheduler ,它是由Spring框架提供的,并且与ThreadPoolTaskExecutor相同。

另一种选择是ScheduledExecutorService ,它由Core Java提供并具有类似的功能。

两种服务都允许您配置线程池大小(500或所需的大小)。 但是请记住,如果您的工作人员在不同的时间范围触发,则可以重用更少量的线程,尤其是当它们长时间不运行时。

另外,请确保拦截所有在工作程序中发生的异常,以免发生意外故障。

有两种常见的模式可以完成此操作:

  1. try / catch块中的环绕工作程序代码:

     public void run() { try { doRun(); } catch (Throwable t) { LOG.error("exception occurred in worker", t); } } 
  2. 使用UncaughtExceptionHandler在所有未拦截异常的线程中拦截和记录故障:

     public class DefaultUncaughtExceptionHandler implements UncaughtExceptionHandler { static { if (Thread.getDefaultUncaughtExceptionHandler() == null) { Thread.setDefaultUncaughtExceptionHandler(new DefaultUncaughtExceptionHandler()); } } @Override public void uncaughtException(Thread t, Throwable e) { if (!(e instanceof ThreadDeath)) { LOG.error("uncaught exception occurred in thread " + t.getName(), e); } } } 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM