[英]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()
可能会导致性能问题。 就我而言,有没有其他选择可以提高性能?
最初,我们使用ThreadPoolTaskExecutor安排了近50个服务。 某些服务无法正常启动。过去1个月我们找不到确切的问题。因此,我们想尝试执行器
您在评论中说您正在使用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);
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或所需的大小)。 但是请记住,如果您的工作人员在不同的时间范围触发,则可以重用更少量的线程,尤其是当它们长时间不运行时。
另外,请确保拦截所有在工作程序中发生的异常,以免发生意外故障。
有两种常见的模式可以完成此操作:
try / catch块中的环绕工作程序代码:
public void run() { try { doRun(); } catch (Throwable t) { LOG.error("exception occurred in worker", t); } }
使用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.