2014-06-26 21 views
-1

我有一個線程,顯示秒錶像減少時間。該線程計數1分鐘。在這一分鐘內,用戶必須回答一個問題。如果用戶在完成一分鐘之前回答問題,則向他顯示下一個問題,並且線程被重置爲計數1分鐘。重新啓動一個線程 - 這是我的頭

我面對的問題是,當我調用reStartTimeKeeper()時,計時器重新啓動,但它開始更快計數。隨後的每一次電話會進一步提高櫃檯的速度。我的意思是,在第一次調用reStartTimeKeeper()之後,我的timmer在30秒(大約)內計數60秒,在第二次調用reStartTimeKeeper()後,我的計時器在15秒內(約)計數60秒。等等。

原因是當我在reStartTimeKeeper()中設置Question_Time = -1時,線程的第一個實例被暫停。它不斷地執行while循環,就好像它正在等待while()中的條件變爲真。

當我嘗試啓動線程的第二個實例時,我設置Question_Time = 60。這啓動線程的新實例。這樣做也會激活正在等待條件成熟的休眠第一個實例。

我只想在任何時間的任何實例的我的線程的1個實例。我把它變成了一個靜態變量。這樣做也沒有效果。

 int Question_Time=-1; 
     static Thread timeKeeper; 
     Handler mHandler = new Handler(); 
     void Start_TimeKeeper() 
     { 
       Question_Time=60; 
      timeKeeper = new Thread(new Runnable() { 
       @Override 
       public void run() { 
        while (Question_Time!=-1) 
        { 
         mHandler.post(new Runnable() 
         { 
          @Override 
          public void run() 
          { 
           Question_Time--; 
           UpdateUI(); 
          } 
         }); 

         try 
         { 
          Thread.sleep((1000)); 
         } 
         catch (InterruptedException e) 
         { 

          e.printStackTrace(); 
         } 
        } 
       } 
      }); 
      timeKeeper.start(); 
     } 

void reStartTimeKeeper() 
{ 
Question_Time=0; 
while(Question_Time==-1); 
Start_TimeKeeper(); 
} 

如果有人能夠同步這個流程,那就太好了! 如果你發現任何愚蠢的東西或改進建議,這將是最受歡迎的。 謝謝!

當我嘗試啓動線程的第二個實例時,我設置Question_Time = 60。這啓動線程的新實例。這樣做也會激活正在等待條件成熟的休眠第一個實例。我想聯合殺死線程的第一個實例,當它被殺死時,我想安全地重新啓動新的實例。

+0

whya不使用CountDownTimer? – Opiatefuchs

+0

我只是有一些空閒時間,我想,用線程做這件事會讓我更好地理解線程。 CountDownTimer可以是我的最後一招!這個任何建議? –

+1

是的,這可能是一個很好的方法,但定時器更準確,你有簡單的解決方案,用cancel()來阻止它們。 – Opiatefuchs

回答

1

當您撥打Start_TimeKeeper();時,它將啓動另一個線程而不停止第一個線程。所以你的兩個線程減少了時間。這就是爲什麼它計數更快。

而不是每次創建一個新的線程,你不能只是檢查舊的線程是否完成,如果是的話,開始一個新的線程,否則只需重置Question_Timeint


class TimeKeeper extends Thread { 

    private volatile boolean run = false; 

    @Override 
    public void run() { 
     run=true;//run while run=true 
     while (run) { 
      if (Question_Time >= 0) { 
       mHandler.post(new Runnable() { 
        @Override 
        public void run() { 
         Question_Time--; 
         UpdateUI(); 
        } 
       }); 
      } 
      try { 
       Thread.sleep(Question_Time >= 0 ? 1000 : 5000);//loop with longer delays if question time is below zero 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 

    public void finish() { 
     run = false; 
    } 

} 

使用此TimeKeeper的類。啓動一次,每次使用,重置變量重新啓動。

+1

其實沒有。他確實試圖通過將計時器設置爲-1來停止舊線程。問題在於這是一個糟糕的機制。 – Ordous

+0

我的線程在這個變量上工作:Question_Time。在reStartTimeKeeper()中,我已經使這個變量爲0,並且我正在等待當前線程將它設置爲-1(循環的終止條件),僅在那之後,我重新啓動線程。所以通過這樣做,我認爲,我完成了舊線程。 –

+0

您需要調用'Thread.join()'以確保您的舊線程完成。但是這是一個非常糟糕的做法。 – Onur

0

兩個主要問題(除了關於整個方法的概念問題):

  1. 沒有同步。正如安迪張貼在他的評論:

    1. 復位計時員被稱爲
    2. 復位設置時間爲0
    3. 計時員設置爲-1
    4. 復位進入循環
    5. 復位設置時間時間到60
    6. 時間保持器進入下一個循環迭代
    7. 復位創建二次時間門將
    8. 利潤! (兩個平行時間守護者)。
  2. 內存可見性。時間是一個非易失性基元。不能保證線索中的while實際上會看到剩餘時間的最新值。

這兩個可以利用你的時間留下了一個原子變量(和你究竟是如何使用它,只是打電話.get()到一個局部變量是行不通的一點思想)來緩解。

更好的方法是不會產生如此多的線程。使用單一時間線程無限循環,並設置布爾標誌 - 遞減計數器。

如果你仍然想生成線程並妥善殺死他們 - 這應該幫助:Stop, interrupt, suspend and resume a java thread