2014-06-17 192 views
0

我希望能夠在依賴相同全局變量的同一時間運行兩個方法。第一種方法定期更新共享變量,但永遠不會結束運行。第二種方法記錄時間。當時間用完時,第二個方法從第一個方法返回共享變量的最後結果。以下是我目前爲止的情況,並在需要幫助的地方註釋了pseduocode。在多個線程之間共享一個對象java

package learning; 

public class testmath{ 
    public static void main(String[] args){ 

     long finishBy = 10000; 
     int currentresult = 0; 

     /* 
     * run eversquare(0) in a seperate thread /in parallel 
     */ 


     int finalresult = manager(finishBy); 
     System.out.println(finalresult); 
    } 


    public static int square(int x){ 
     return x * x; 
    } 

    public static void eversquare(int x){ 
     int newresult; 
     while(2 == 2){ 
      x += 1; 
      newresult = square(x); 
      /* 
      * Store newresult as a global called currentresult 
      */ 

     } 
    } 



    public static int manager(long finishBy){ 


     while(System.currentTimeMillis() + 1000 < finishBy){ 
      Thread.sleep(100); 
     } 

     /* 
     * Access global called currentresult and create a local called currentresult 
     */  
     return currentresult; 

    } 

} 
+1

爲什麼'while(2 == 2)'而不是'while(true)'?請記住,您可以同步方法內的塊,而不僅僅是整個方法。 –

+2

閱讀併發教程,並嘗試一些:http://docs.oracle.com/javase/tutorial/essential/concurrency/index.html –

+0

@PatriciaShanahan它們具有等同的布爾值,將來會使用true。在三天前開始學習java,你能否再解釋一下你的意思是「你可以在一個方法中同步一個塊,而不僅僅是一個完整的方法」,以及它如何幫助我。 – Michael

回答

2

你只需要運行一個附加線程:

public class Main { 
    /** 
    * Delay in milliseconds until finished. 
    */ 
    private static final long FINISH_BY = 10000; 
    /** 
    * Start with this number. 
    */ 
    private static final int START_WITH = 1; 
    /** 
    * Delay between eversquare passes in milliseconds. 
    */ 
    private static final long DELAY_BETWEEN_PASSES = 50; 
    /** 
    * Holds the current result. The "volatile" keyword tells the JVM that the 
    * value could be changed by another thread, so don't cache it. Marking a 
    * variable as volatile incurs a *serious* performance hit so don't use it 
    * unless really necessary. 
    */ 
    private static volatile int currentResult = 0; 

    public static void main(String[] args) { 
    // create a Thread to run "eversquare" in parallel 
    Thread eversquareThread = new Thread(new Runnable() { 
     @Override public void run() { 
     eversquare(START_WITH, DELAY_BETWEEN_PASSES); 
     } 
    }); 

    // make the eversquare thread shut down when the "main" method exits 
    // (otherwise the program would never finish, since the "eversquare" thread 
    // would run forever due to its "while" loop) 
    eversquareThread.setDaemon(true); 

    // start the eversquare thread 
    eversquareThread.start(); 

    // wait until the specified delay is up 
    long currentTime = System.currentTimeMillis(); 
    final long stopTime = currentTime + FINISH_BY; 
    while (currentTime < stopTime) { 
     final long sleepTime = stopTime - currentTime; 
     try { 
     Thread.sleep(sleepTime); 
     } catch (InterruptedException ex) { 
     // in the unlikely event of an InterruptedException, do nothing since 
     // the "while" loop will continue until done anyway 
     } 
     currentTime = System.currentTimeMillis(); 
    } 
    System.out.println(currentResult); 
    } 

    /** 
    * Increment the value and compute its square. Runs forever if left to its own 
    * devices. 
    * 
    * @param startValue 
    * The value to start with. 
    * 
    * @param delay 
    * If you were to try to run this without any delay between passes, it would 
    * max out the CPU and starve any other threads. This value is the wait time 
    * between passes. 
    */ 
    private static void eversquare(final int startValue, final long delay) { 
    int currentValue = startValue; 
    while (true) { // run forever (just use "true"; "2==2" looks silly) 
     currentResult = square(currentValue); // store in the global "currentResult" 
     currentValue++; // even shorter than "x += 1" 
     if (delay > 0) { 
     try { // need to handle the exception that "Thread.sleep()" can throw 
      Thread.sleep(delay); 
     } catch (InterruptedException ex) { // "Thread.sleep()" can throw this 
      // just print to the console in the unlikely event of an 
      // InterruptedException--things will continue fine 
      ex.printStackTrace(); 
     } 
     } 
    } 
    } 

    private static int square(int x) { 
    return x * x; 
    } 
} 

我還要提到的是,「揮發性」關鍵字工程(大多數)原語,因爲任何JVM你會看到這幾天的保證他們將被原子地修改。對象不是這種情況,您需要使用同步塊和鎖以確保它們總是以一致的狀態「看到」。

大多數人也提到,你真的應該使用的方法本身的​​關鍵字,並在特定的「鎖定」對象,而不是同步。通常這個鎖對象不應該在你的代碼之外可見。這有助於防止人們錯誤地使用你的代碼,使自己陷入困境,然後試圖責怪你。 :)

+0

這非常有幫助。唯一不清楚的是爲什麼延遲是必要的。我的理解是,添加多個線程可以讓程序使用計算機的多個CPU。當我讀取你的代碼時,每當它返回一個值時關閉函數50毫秒就會浪費寶貴的計算時間。我想這取決於程序的用途以及運行的不同類型的機器。 – Michael

+0

這顯然是一個玩具的例子,'DELAY_BETWEEN_PASSES = 0'函數可以達到1516175360,延遲50毫秒,它只能達到40401. – Michael

+0

@Michael:由於Java(理論上)可以在任何地方運行,所以你可以不會對底層操作系統和CPU做任何假設。由於越來越多的人正在部署「雲」,這一點尤其如此。如果碰巧在只有一個內核可用的情況下運行,eversquare線程可能會佔用太多的CPU時間,「main」方法/線程可能永遠不會獲得足夠的CPU時間來喚醒,或者可能會遲到。即使在具有多個內核的機器上,AFAIK JVM也沒有義務將它們用於其線程。有人糾正我,如果我錯了。 –

相關問題