class ABC implements Runnable {
private static int a;
private static int b;
public void run() {
}
}
我有一个如上所述的Java类。我有这个类的多个线程。在run()
方法中,变量a
& b
每次递增几次。在每个增量上,我将这些变量放在Hashtable中。
因此,每个线程都会增加两个变量并将它们放在Hashtable中。如何使这些操作线程安全?
答案 0 :(得分:10)
我会使用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
答案 1 :(得分:9)
取决于需要线程安全的内容。对于这些int
原语,您需要将它们替换为AtomicInteger
,或者仅在synchronized
方法或块中使用它们。如果你需要让你的跨线程Hashtable线程安全,你不需要做任何事情,因为它已经同步。
答案 2 :(得分:6)
使用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
}
}
注意:这些方法假设您希望在一个原子操作中增加a
和b
,其他答案将突出显示它们单独>的方式使用原子增加。
答案 3 :(得分:2)
我想补充一些关于这个问题答案的细节。
首先,OP正在询问:
如何让这些操作线程安全?
在回答这个问题之前,我们需要达到线程安全的一致性。我最喜欢的定义是“Java Concurrency In Practice”和它的
如果一个类在访问时行为正确,则它是线程安全的 来自多个线程,无论是调度还是 由运行时交错执行这些线程 环境,没有额外的同步或其他 调用代码的协调。
如果您同意该定义,则意味着我们在进一步讨论之前达成一致性。让我们回到你想要的操作,它是a++
和b++
,在增加之后,你会将它们放入HashTable
。
对于a++
操作,它实际上不是单个操作。它遵循读取修改写入的模型。如您所见,它实际上包含三个单独的步骤。读取值,添加一个值并保存回来。如果有两个线程同时读取变量a
并且值1
,则在修改和保存后操作之后。该值为2
,但实际上应为3
。为避免出现这种情况,与其他人建议的情况一样,您可以直接使用AtomicInteger
代替int
类型。 AtomicInteger
将保证一些操作,如增量以原子方式执行。这意味着,读取修改写入操作无法分割,并将作为一个单独的步骤执行
之后,OP希望将值保存到HashTable中。 HashTable是一个线程安全的容器,不需要其他同步
希望这个澄清可以帮助别人以其他方式。感谢。