2012-04-17 129 views
4

我是Java中的新手,我以前沒有使用過線程。現在我對我的知識水平有一個非常棘手的問題。使用多個實例同步兩個定時器(Java)

我開發了兩個功能「發送郵件」和「檢查郵件」。每個用戶登記自己的喜好和系統創建兩個目錄與​​定期工作多次批示像

A)發送消息,每隔1500毫秒

B)發送消息每1800毫秒

C)發送消息每隔3000毫秒

而且 A)檢查消息每2000毫秒

B)檢查消息每6000毫秒

C)每8000毫秒檢查一次消息

我嘗試了很多使用線程的方法,但是我無法做到這一點。 我的問題是哪個是同步它們的最佳方法?下面是我使用線程的最後努力的代碼。

public class MailCreatorThread extends Thread { 
    @Override 
    public void run() { 
     CreateMail(_date); //creates a mail with _date as subject 
    } 
} 

public class GPSThread extends Thread { 
    @Override 
    public void run() { 
     // TODO Auto-generated method stub 
     while (!_isTimeToStop) { 
      try { 
       while (_servicesToUpdate.size() == 0) { 
        Thread.sleep(500); 
       } 
       _currentService = (MyService) _servicesToUpdate.get(0) 
         .clone(); 
       _servicesToUpdate.remove(0); 

         MailCreatorThread mailCreatorThread = new MailCreatorThread(); 
         mailCreatorThread.start(); 


      } catch (InterruptedException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 
     } 
    } 
} 

public class CheckServicesThread extends Thread { 
    @Override 
    public void run() { 
     // TODO Auto-generated method stub 
     while (!_isTimeToStop) { 
      try { 
       Thread.sleep(1000); 
        for (int j = 0; j < _servicesList.length; j++) { 
         MyService currentService = ((MyService) _servicesList[j]); 
         if (myService.getTimeToNextUpdate() - 1000 <= 0) { 
          _servicesToUpdate 
            .add((MyService) currentService 
              .clone()); 
          currentService 
            .setTimeToNextUpdate(currentService 
              .getUpdatePeriod()); 
         } else { 
          currentService 
            .setTimeToNextUpdate(currentService 
              .getTimeToNextUpdate() - 1000); 
         } 
       } 

      } catch (InterruptedException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 
     } 
     stopSelf(); 
    } 
} 

回答

4

您可以使用ScheduledExecutorService來運行週期性任務。語法是相當簡單:

Runnable check = new Runnable() { 
    public void run() { 
     checkMessage(); 
    } 
} 
Runnable send = new Runnable() { 
    public void run() { 
     sendMessage(); 
    } 
} 

//since what you are doing is mostly I/O you probably want to have 
//more than one thread available so that if one operation blocks, 
//the other ones can be launched in parallel 

ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(10); 
scheduler.scheduleAtFixedRate(check, 0, 1500, MILLISECONDS); 
scheduler.scheduleAtFixedRate(send, 0, 6000, MILLISECONDS); 

注:Ozzy's answer提到Timer不應該使用更多的,因爲它已經在Java 1.5中通過ScheduledThreadPoolExecutor進行了改進,如Timer's javadoc解釋說:

Java 5.0中引入了java.util。併發包和其中的一個併發實用程序是ScheduledThreadPoolExecutor,它是用於以給定速率或延遲重複執行任務的線程池。它實際上是Timer/TimerTask組合的更多功能的替代品,因爲它允許多個服務線程,接受各種時間單位,並且不需要子類化TimerTask(僅實現Runnable)。使用一個線程配置ScheduledThreadPoolExecutor使其等同於Timer。

+0

謝謝! 我試過你的解決方案,它效果很好! – Bilias7 2012-04-19 19:01:24

3

在java中,你有內置的Timer和TimerTask類來幫助你在一個單獨的線程中重複一個任務。

這將創建一個定時器,這將創造自己的背景主題:

Timer t = new Timer(); 

然後,您可以根據需要與該定時器安排儘可能多的任務,他們將分享計時器的自己的線程。

這是你如何安排計時器線程上一個任務中,2000毫秒= 2秒延遲後:

t.schedule(new TimerTask() { 
    @Override 
    public void run() { 
     //task to perform 
    } 
}, 2000); 

這是你如何安排重複任務計時器線程上,後1秒的延遲,重複任務,以1.5秒的時間間隔:

t.scheduleAtFixedRate(new TimerTask() { 
    @Override 
    public void run() { 
     //task to perform every 1.5 seconds 
    } 
}, 1000, 1500); 

現在你有一個選擇來安排這兩項任務(checkMail,sendmail)在相同的定時器(同一個線程),或給他們每個自己的計時器(單獨的線程)。

欲瞭解更多信息,請參閱Java文檔(http://docs.oracle.com/javase/6/docs/api/java/util/Timer.html)

希望這有助於。

+0

你應該推薦使用'ScheduledThreadPoolExecutor'而不是'Timer'用於Java 1.5+ - 查看我的答案。 – assylias 2012-04-17 18:59:23

+0

奧茲感謝您的時間! 我試過你的解決方案,它的工作原理與你描述的 完全一樣,但是在java中進行了一些搜索之後,我將它作爲assylias進行檢索,說ScheduledExecutorService是推薦的工具。 – Bilias7 2012-04-19 19:03:52