2014-11-17 34 views
2

我遇到了一個我的程序問題。總和數據在多個線程之間共享。它應該在每個線程添加到之後給出總和。線程之間的共享數據不對

public class ThreadPractise implements Runnable 
{ 
    Integer num; 
    String name; 
    volatile Integer commonSum; 
    Object lock; 

    public ThreadPractise(Integer i,String threadName ,Integer sum, Object sharedLock) { 
     num = i; 
     name = threadName; 
     commonSum =sum; 
     lock = sharedLock; 
    } 

    @Override 
    public void run() { 
     Integer cube = calculate(num); 
     update(cube); 
     System.out.println(Thread.currentThread().getName()+" has commonSum after update as "+commonSum); 
    } 

    public void update(Integer cube) { 
     synchronized (lock) { 
      this.commonSum = this.commonSum + cube; 
      System.out.println(Thread.currentThread().getName()+" has commonSum as "+commonSum); 
     } 
    } 
    public int calculate(Integer num2) { 
     return (num2*num2*num2); 
    } 

    public static void main(String[] args) { 

     Integer sum = new Integer(0); 
     Object lock = new Object(); 
     for(int i=1;i<=3;i++) 
     { 
      Thread t = new Thread(new ThreadPractise(i, "Thread"+i, sum,lock)); 
      t.start(); 
      try { 
       t.join(); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 

     System.out.println("Sum of 1^3+2^3+3^3 = "+sum); 

    } 

} 

然而總和始終爲0。當我改變到的AtomicInteger其工作,但我需要的問題,這個實現。也請告訴我,我正在做的線程鎖定是否正確。

回答

4

您的問題與併發性無關。看看你的main方法。它有一個局部變量sum。這個局部變量從不更新。相反,您正在更改ThreadPractise實例引用的num字段的對象。該值使用sum的值進行初始化,但是一旦您替換值num,則其值不再與sum相關,因爲該值已被替換,但未更新。因此,打印的值仍爲0,這是原來分配給sum的值。

你要做的就是簡單地說什麼:

Integer a = 0; 
Integer b = a; 
b = 1;     // does not change a 
System.out.println(a); // prints '0' 

但在Java中,你不能改變由一個變量沒有給這個變量分配一個新的值參考的價值。

與此相反,AtomicInteger您將可變的實例傳遞給您的線程。而不是替換num引用的值,您現在正在更新這個非常相同的實例所代表的值。這樣,numsum變量保持相同,因爲它們引用同一個對象。 Integer這是不可變的這種方法是不可能的。如果Integer類具有類似setValue(int)的方法,則您正在執行的操作將與sumnum類似地引用同一對象一樣。

+0

非常感謝。只是爲了增加這個問題。我對線程相對來說比較陌生。是我在程序中正在執行的鎖定權限。 – HariJustForFun

+0

也只是一個懷疑的答案。我只在main中使用new關鍵字一次。然後,執行線程的變量版本是什麼。 – HariJustForFun

+0

通常,您應該只鎖定「final」字段以確保始終鎖定在同一個實例上。除此之外,你的代碼看起來是正確的。然而,使用'AtomicInteger'將是更好的方法來處理併發,因爲它是* lock free *,因此運行更高性能。 –

2

Integer是不可變的。您無法將Integer傳遞到方法中,並期望以這種方式獲得更新版本。

如果你不想使用AtomicInteger(這是可更新的,甚至以線程安全的方式,這將是我的首選解決方案),你需要從每個線程檢索部分總和或讓線程在某處更新通用累加器(例如,使commonSum靜態)。

2

Integer對象是不可變的。雖然Thread中存在的Integer實例最初與您在主方法中聲明的實例相同,但每當其值更改時(即每次添加到commonSum時)都將其替換爲新實例。你的所有線程都會持有對不同Integer對象的引用,並且主方法中的實例將不受影響。

您必須將Integer包裝成某種對象才能在主要方法和線程之間共享它。 AtomicInteger就是這麼做的,而且作爲額外的好處,它將爲你做所有的同步。

+0

謝謝,我明白了。這是我之前詢問的其中一條評論的答案。 – HariJustForFun