2014-02-26 96 views
0

我有一个计数器和多个线程访问getCount方法。代码如下:是没有任何参数线程安全的静态方法?

public class ThreadSafeMethod { 

     public static int counter = 0; 

     public static int getCount() { 
      return counter++; 
     } 
    } 

该方法线程安全吗?我的理解是,因为counter++不是自动的,所以不安全。那么如何让它安全?如果我们添加​​关键字,什么对象会被同步?

回答

5

当你说它不是线程安全的,因为操作不是原子的时候,你的分析是正确的。值和增量的检索不是线程安全的。对这个方法的多次调用(不管它是否有参数)都访问同一个非局部变量。

将​​添加到此方法使其成为线程安全的。当添加到static方法时,那么Class对象是被锁定的对象。

使其线程安全的替代方法是用AtomicInteger代替int,该代码具有其自己的原子getAndIncrement方法。

3

没有,一个无参数的方法是本质上就是线程安全的 - 缺少参数使得在这个例子中没有什么区别。

从读(或写)的counter变量是保证是线程之间的任一方原子一致

最简单的变化是简单地make the method synchronized

public static synchronized int getCount() { 
    return counter++; 
} 

(最简单的是并不总是“最佳”或“正确的”,但是这将是足够的这里,假设没有其他代码接触公开counter变量。)

请参阅this answer了解静态方法的同步如何工作 - 可以想象,它是用作监视器的类本身。

1

在静态函数中使用synchronized关键字会将函数'锁定'到一个线程,以确保两个线程不会混淆同一个变量。根据你的建议,我相信任何在该函数中被访问或修改的东西都是线程安全的。

+1

“在该函数中获取或修改的任何内容都将是线程安全的。” - 只要一个线程在任何给定的时间在上面的例子中都可以输入getCount()(如果它是在类对象上同步的),但这不会使count变量线程安全。如果其他一些方法也直接访问count变量呢?如果触及它的_every_方法锁定_same lock_,该变量只能是线程安全的。 –

1

正如你所说的counter++操作是非原子的,所以一次给多个线程访问会导致未定义的行为。在线程安全中,问题几乎总是对共享资源(如静态变量)进行同步访问。

线程在声明方法​​时获取的锁属于该类。假设我们有一个类

public synchronized void foo() {...} 
public synchronized void bar() {...} 

两种方法如果一个线程进入foo()获取到了类的锁,任何其他线程试图访问foo()ORbar()将阻塞,直到第一个线程完成。为了克服这个问题,我们可以锁定方法中的独立对象。

// Declare 2 objects to use as locks within the class 
private Object fooLock = new Object(); 
private Objecy barLock = new Object(); 

// lock on these objects within the method bodies 
public void foo { 
    synchronized(fooLock) { /* do foo stuff */ } 
} 

public void bar() { 
    synchronized(barLock) {/* do bar stuff */} 
} 

现在2个线程可以在foo()bar()同时访问。

网上有很多关于线程安全的资料,如果你想更多地了解有关锁/执行器服务和东西的多线程,我会推荐this一组教程。