2015-08-09 50 views
3

有了這個簡單的類,用另外的方法:簡單添加方法線程安全嗎?

class A { 
    public Integer add (int a, int b){ 
    return a+b; 
    } 
} 

是線程安全的或不..?它對我來說看起來很安全,但大多數人回答不,任何人都可以解釋爲什麼?

+0

http://stackoverflow.com/q/6324085/4506140 –

回答

2

它完全是線程安全的,因爲所有變量都是本地的。

+0

這就是我還以爲 –

+0

,這是真的) – ka4eli

3

只有當你有一些共享狀態的手段並且你沒有任何鎖定或同步,即修改一個共享變量(類級別變量)時,你應該關心線程安全性。
這裏沒有線程安全的問題。
而在這種特殊情況下每個變量是局部的,該位置不會被線程共享的每個函數調用都會對堆棧單獨分配他們連同他們的局部變量你不應該打擾反正:)

+0

感謝您的詳細信息 –

+0

你** **認爲這種說法是真實的,但實際上它不是,請參閱[codegolf的答案*編寫一個使2 + 2 = 5 *的程序](http://codegolf.stackexchange.com/a/28818/29280) – fabian

+1

從線程安全的角度來看,它是一個真正的線程安全代碼。而你(@fabian)上面提到的反射代碼,反射既不是爲了那個,也不是它對它的良好使用。我同意你總能用反思產生邪惡。但是,這是不建議的。 –

2

實際上,這種方法不是線程安全的,但它需要您瞭解一些關於Integer類的內部,以瞭解原因。讓我們來看看一些代碼,產生相同的字節碼:

class A { 
    public Integer add (int a, int b){ 
    // auto boxing hidden in OP's implementation 
    return Integer.valueOf(a+b); 
    } 
} 

足夠小的值Integer s的高速緩存和陣列中擡起頭來。使用反射可以訪問該數組並更改其元素。 這些更改不會同步,因此如果您更改這些元素,則可能會從另一個線程更改方法的結果。

下面的代碼應該演示大多數Java VM上的問題:您的方法中存在競爭條件。在大多數情況下,它會打印4S和5S:

import java.lang.reflect.Field; 

class A { 

    public Integer add(int a, int b) { 
     return a + b; 
    } 

    private static volatile boolean cont = true; 

    public static void main(String[] args) throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException, InterruptedException { 
     final A a = new A(); 

     new Thread(() -> { 
      while(cont) { 
       for (int i = 0; i < 100; i++) { 
        // print result of add method 
        System.out.println(a.add(2,2)); 
       } 
      } 
     }).start(); 

     // give other thread time to start 
     Thread.sleep(1); 

     // mess around with the internals of Integer 
     Class cache = Integer.class.getDeclaredClasses()[0]; 
     Field c = cache.getDeclaredField("cache"); 
     c.setAccessible(true); 
     Integer[] array = (Integer[]) c.get(cache); 
     array[132] = array[133]; 

     cont = false; 
    } 
} 

然而,在大多數情況下,沒有人與周圍的Integer的內部食堂。如果Integer類中的數組永遠不會被修改,則由方法返回的Integer對象包裝的值始終是正確的,因爲Integer.valueOf所使用的共享狀態永遠不會被修改。因此在這種情況下它將是線程安全的。

+0

所以我們可以說它是安全的,除非我們陷入反思? –

+0

@NassimMOUALEK,這不是關於「與反射混亂」。 Fabian的例子是顛覆Integer類,以便Integer對象具有不同於通常所期望的值。也就是說,他正在盜用它來返回_wrong_值,然後他說,注意,因爲他的黑客不一定會在不同的線程中產生相同的_same_錯誤值。 「反思」不是問題。問題在於他使用反射_for_。 –

+0

好吧,這個問題是一個recruter的問題,我只是問什麼是最好的答案,我們不能說它不是線程安全的,好的迴應,是的,除非我們反思 –