2013-10-18 44 views
0

以下程序執行基本的多線程任務。我在一個類中有兩個線程。一個線程負責增加一個值變量,另一個線程檢查值並顯示一條消息。爲什麼在多個線程之間不更新值?

Class Was{ 
private int ctime; 
private int value; 
public Thread w,c; 

public was(int a) { 
    ctime=a; 
    w = new Thread(new Runnable() {   
     public void run() { 
      try { 
       for(int i=0;i<5;i++) { 
        Thread.sleep(ctime*1000); 
        value++; 
       } 
       System.out.printf("\nIncreasing done"); 
      } catch(InterruptedException e) { 
       System.out.println(e); 
      } 
    } 
    }); 

    c = new Thread(new Runnable() {   
     public void run() { 
      try { 
       for(;;) { 
        if(value==3) { 
         w.wait(); 
         System.out.printf("\nValue reached"); 
         w.notify(); 
         break; 
        } 
       } 
      } catch(InterruptedException e) { 
       System.out.println(e); 
      } 
     } 
    }); 
} 

main class

class Main{ 
    public static void main(String z[]) { 
     Scanner s = new Scanner(System.in); 
     int temp; 
     System.out.printf("\nEnter the sleeping time in seconds: "); 
     temp=s.nextInt(); 
     was m = new was(temp); 
     m.w.start(); 
     m.c.start(); 
    } 
} 

的C線程永遠不會告訴的價值已經達到了。我不懂爲什麼。

+3

請遵循Java命名約定,類以大寫字母開頭。請格式化您的代碼。 –

+0

這個[示例](http://arashmd.blogspot.com/2013/06/java-threading.html#synctr1)可能會有所幫助。 – 2013-10-18 12:44:09

回答

8

c線程永遠不會告訴已達到該值。我不懂爲什麼。

當您在線程之間共享值時,您需要使用某種機制來同步保存該值的內存。這可以通過synchronize塊完成,將值標記爲volatile,或使用(在本例中)爲AtomicInteger。這是一個good tutorial on the memory consistency

AtomicInteger在這裏使用是正確的,因爲它允許線程安全地增加。你必須記住,增量是而不是原子操作,因爲它確實是獲取,增加和設置。

您的代碼看起來是這樣的:

private final AtomicInteger value = new AtomicInteger(0); 
... 
value.incrementAndGet(); 
... 
if (value.get() == 3) ... 

此外,作爲@Boris指出你有下面的代碼:

w.wait(); 
System.out.printf("\nValue reached"); 
w.notify(); 

這不能編譯,因爲你是不是在​​塊。此外,有wait(),然後notify()是有點奇怪的模式。您可能還想閱讀tutorial on guarded blocks

+1

在'Thread'對象的'synchronized'阻塞之外還有'wait'和'notify'的用法 - 我不確定'int'是唯一的問題。 –

+0

出於好奇,在過去的3分鐘裏,你已經編輯了5次或6次的答案,在答案中一直添加更多內容的原因是什麼?我可能是我們兩個人之間的「新的孩子」,但是,儘快「儘快得到答案」,然後在答案中加入所有*重要*點是很常見的。 – Izmaki

+1

爲OP提供一點背景知識:幾乎所有當今的CPU都有多個內核,每個內核都有自己的緩存來加速訪問最近使用的變量。因此,從一個線程更改變量並不一定意味着不同的線程會看到它;新值可能只存在於變異線程的緩存中,另一個線程可能在不同的核心上運行。但是,默認情況下使所有內容同步將會造成巨大的性能下降,並且會降低單線程程序的速度,因此您必須自己指定它。 – Doval

0

我對代碼進行了更改,需求相同但設計不同。所以我所理解的是線程W和C應該共享同一個監視器,通過這個監視器可以在其他信號發出時通知它。所以在這種情況下,對象鎖作爲監視器。我將Object的相同實例(鎖)傳遞給線程,並在該鎖上調用wait和notify。它工作正常。 package com.stackoverflow.gin;

public class Main { 

    private Object lock = new Object(); 
    private C c = new C(lock); 
    private W w = new W(lock); 

    public static void main(String[] args) { 
     Main u = new Main(); 
     u.start(); 
    } 

    public void start() { 
     System.out.println("Start"); 
     c.start(); 
     w.start(); 
    } 

    public class W extends Thread { 
     private Object lock; 

     public W(Object lock) { 
      this.lock = lock; 
     } 

     @Override 
     public void run() { 
      try { 
       for (;;) { 
        Thread.sleep(1000); 
        System.out.println("Notify C that I have finished work"); 
        synchronized (lock) { 
         lock.notify(); 
        } 
       } 
      } catch (Exception e) { 
       System.out.println(e.getMessage() + "W"); 
      } 
     } 
    } 

    public class C extends Thread { 
     private int times = 0; 
     private Object lock; 

     public C(Object lock) { 
      this.lock = lock; 
     } 

     @Override 
     public void run() { 
      try { 
       for (;;) { 
        System.out.println("Waiting for W to finish "); 
        synchronized (lock) { 
         lock.wait(); 
        } 
        System.out.println("W has notified " + times); 
        times++; 
        if (times == 3) { 
         System.out.println("Every thing is done, lets die to gether"); 
         System.exit(0); 

        } 
       } 
      } catch (Exception e) { 
       System.out.println(e); 
      } 
     } 
    } 

} 
+0

我其實想讓線程c檢查值是否已達到3.如果是這樣,使線程暫時等待並打印一條消息,然後恢復線程w以完成將其值更新爲5的任務。 製作完成後變量值原子i可以在Value中實現同步。但是當我使用w.wait()時,我得到非法monitorstate異常。我需要通過實際製作w線程來完成一項任務。如果你能幫助我在新設計或我的設計中實現它,那將是非常好的。 – Ragz

0

我不認爲你可以或應該把一個線程等待從其他線程。它就像兩輛公交車並行,一輛公共汽車想要在其他地方停下來。那沒有意義。或者它不是一個好的設計。我不知道以下是你在找什麼,但有一個看看,讓我知道。

import java.util.concurrent.atomic.AtomicInteger; 

public class Main { 

    private Object lock = new Object(); 
    private C c = new C(lock); 
    private W w = new W(lock); 
    private AtomicInteger times = new AtomicInteger(); 

    public static void main(String[] args) { 
     Main u = new Main(); 
     u.start(); 
    } 

    public void start() { 
     System.out.println("Start"); 
     c.start(); 
     w.start(); 
    } 

    public class W extends Thread { 
     private Object lock; 

     public W(Object lock) { 
      this.lock = lock; 
     } 

     @Override 
     public void run() { 
      try { 
       for (int i = 0; i < 5; i++) { 
        Thread.sleep(1000); 
        times.set(i + 1); 
        System.out.println("Incremented counter " + times.get()); 
       } 
       synchronized (lock) { 
        System.out.println("Notify C that I have finished work"); 
        lock.notify(); 
       } 
      } catch (Exception e) { 
       System.out.println(e.getMessage() + "W"); 
      } 
     } 
    } 

    public class C extends Thread { 
     private Object lock; 

     public C(Object lock) { 
      this.lock = lock; 
     } 

     @Override 
     public void run() { 
      try { 
       for (;;) { 
        if (times.get() == 3) { 
         synchronized (lock) { 
          System.out.println("Now I will wait until W finishes with his work"); 
          lock.wait(); 
          System.out.println("Ok W is finished with the loop " + times.get() + " lets exit the sytem."); 
          System.exit(0); 
         } 
        } 
       } 
      } catch (Exception e) { 
       System.out.println(e); 
      } 
     } 
    } 

} 
+0

謝謝......你的設計爲我工作!非常感謝您的幫助。 – Ragz

相關問題