静态变量的线程安全性
class ABC implements Runnable { private static int a; private static int b; public void run() { } }
我有一个如上所述的Java类。 我有这个类的多个线程。 在run()
方法中,变量a
和b
每次递增几次。 在每个增量上,我将这些变量放在Hashtable中。
因此,每个线程都会增加两个变量并将它们放在Hashtable中。 如何使这些操作线程安全?
我会使用AtomicInteger ,它设计为线程安全的并且易于使用并且给应用程序带来绝对最小的同步开销:
class ABC implements Runnable { private static AtomicInteger a; private static AtomicInteger b; public void run() { // effectively a++, but no need for explicit synchronization! a.incrementAndGet(); } } // In some other thread: int i = ABC.a.intValue(); // thread-safe without explicit synchronization
取决于什么需要线程安全。 对于这些int
原语,您需要将它们替换为AtomicInteger
,或者仅在synchronized
方法或块中使用它们。 如果你需要让你的跨线程Hashtable线程安全,你不需要做任何事情,因为它已经同步。
使用synchronized
方法,例如
public synchronized void increment() { a++; b++; // push in to hash table. }
如果你通过单个实例访问静态,上面是好的,但是如果你有多个实例,那么你需要在一些静态对象上进行同步 – 比如(未经测试)。
private static Object lock = new Object();
在方法中
public void increment() { synchronize(lock) { a++;b++; // do stuff } }
注意:这些方法假设您希望在一个primefaces动作中增加a
和b
,其他答案突出显示如何使用primefaces单独增加它们。
我想补充一些关于这个问题答案的细节。
首先,OP询问:
如何使这些操作线程安全?
在回答这个问题之前,我们需要达到线程安全的一致性。 我最喜欢的定义是“Java Concurrency In Practice”中的定义
如果一个类在从多个线程访问时行为正确,则它是线程安全的,无论运行时环境是否调度或交错执行这些线程,并且调用代码没有额外的同步或其他协调。
如果您同意该定义,则意味着我们在进一步讨论之前达到一致性。 让我们回到你想要的操作,它是a++
和b++
,在增量之后,你将它们放入一个HashTable
。
对于a++
操作,它实际上不是单个操作。 它遵循读取修改写入的模型。 如您所见,它实际上包含三个单独的步骤。 读取值,添加一个并保存。 如果有两个线程在修改和保存后操作之后同时读取值为1
的变量a
。 值为2
,但实际应为3
。 为了避免这种情况发生,就像其他人建议的那样,您可以直接使用AtomicInteger
而不是int
类型。 AtomicInteger
将保证一些操作,如增量以primefaces方式执行。 这意味着, 读取修改写入操作不能被划分,并且将作为一个单独的步骤执行。
之后,OP希望将值保存到HashTable中。 HashTable是一个线程安全的容器,不需要其他同步。
希望这个澄清可以帮助别人以其他方式。 谢谢。