2015-08-09 52 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的问题,我只是问什么是最好的答案,我们不能说它不是线程安全的,好的回应,是的,除非我们反思 –