2016-11-15 54 views
1

我在我的應用程序中使用了Spring ThreadPoolTask​​Executor。我的方法的一個方法需要僅在週五午夜之前調用。該方法被調用服務器startup.So我現在用的是Thread.sleep()以下列方式Java中的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 month.So確切的問題,我們希望與執行嘗試

請參閱本Spring scheduler is stopping unexpectedly and starting again

+0

對於需要在特定日期的特定時間定期運行的程序,您應該使用quartz scheduler或cron。 – RealSkeptic

+0

「提高性能」?如果你睡了一天,表現真的不是問題。您遇到的更大問題是確保您的JVM仍在運行。 –

+0

我會親自使用cronjob,調度程序,ExecutorService或類似的東西。因爲Thread.sleep一週看起來很浪費。 –

回答

1

你在你的評論說你正在使用彈簧。所以你可以使用cron表達式。有關如何使用Scheduler的更多詳細信息,請參閱34. Task Execution and Scheduling

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

這將使它每週在星期五凌晨1點運行。您可以使用Cron Maker來生成表達式。

在您的配置類中,您必須啓用調度。

@Configuration 
@EnableAsync 
@EnableScheduling 
public class AppConfig { 
} 
+0

感謝Murat.But有沒有使用調度的可能性,即執行者 – PSR

+0

@PSR爲什麼你要避免使用調度程序?它屬於同一個框架,並且它是該框架中用於在給定日期和時間運行任務的正確工具。 – RealSkeptic

+0

@PSR避免調度程序是沒有意義的,因爲它會像你想做的那樣完成。 –

0

您可以使用ScheduledExecutorService安排工作在一段時間後進行。

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

注意:如果你希望發生在每週五的午夜(因此不只是本週五)的工作,你可以修改日程安排命令在設定的時間間隔發生:

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

使用一個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重新安排下一次執行的任務。

0

根據其他用戶的建議使用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); 
         } 
        } 
    }