5

在像 Android 这样的多线程环境中,一个简单的int变量可以由多个线程操作,在某些情况下仍然可以使用 anint作为数据成员吗?

Anint作为局部变量,仅限于对其具有独占访问权限的方法的范围(因此修改它的开始和结束总是在同一个线程中),在性能方面非常有意义。

但作为数据成员,即使被访问器包装,也会遇到众所周知的并发交错修改问题。

因此,看起来“稳妥行事”,人们可以AtomicInteger全面使用。但这似乎非常低效。

你能举一个线程安全int数据成员使用的例子吗?

4

5 回答 5

8

是否有任何理由不总是使用 AtomicInteger 作为数据成员?

是的,有充分的理由总是使用AtomicInteger. 由于构造比本地构造和用于设置/获取基础值 的其他构造,它AtomicInteger可以至少慢一个数量级(可能更多) 。意味着每次访问时都会跨越内存屏障,这会导致相关处理器上的缓存内存刷新。volatileintUnsafeintvolatileAtomicInteger

此外,仅仅因为您已将所有字段都设置为,AtomicInteger并不能在访问多个字段时保护您免受竞争条件的影响。对于何时使用volatile,synchronizedAtomic*类做出正确的决定是无可替代的。

例如,如果您希望在线程程序中以可靠的方式访问一个类中有两个字段,那么您将执行以下操作:

synchronized (someObject) {
   someObject.count++;
   someObject.total += someObject.count;
}

如果这两个成员都具有,AtomicInteger那么您将访问两次,因此跨越 2 个内存障碍,而不仅仅是 1 个。此外,分配volatile比. 此外,由于这两个操作的数据竞争条件(与上面的块相反),您可能无法获得正确的.UnsafeAtomicIntegersynchronizedtotal

你能举一个线程安全的 int 数据成员使用的例子吗?

除了制作它之外finalint除了标记它volatile或使用AtomicInteger. 没有什么神奇的方法可以在所有字段上绘制线程安全。如果有那么线程编程将很容易。挑战在于找到放置synchronized积木的正确位置。找到应该用 标记的正确字段volatile。找到合适的地方使用AtomicInteger和朋友。

于 2012-06-20T18:02:56.983 回答
1

如果您有有效的不可变ints,您可以避免以计算成本为代价不确保同步。一个例子是hashCode

int hash = 0;

public int hashCode(){
   if(hash == 0){
     hash = calculateHashCode(); //needs to always be the same for each Object
   }
   return hash;
}

这里明显的权衡是对同一个哈希值进行多次计算的可能性,但如果替代方案是哈希码,则synchronized可能会产生更糟糕的影响。

这在技术上是线程安全的,尽管是多余的。

于 2012-06-20T18:07:07.143 回答
0

线程安全不仅与原子 int 分配有关,还需要仔细设计锁定模式以使代码保持一致。

如果您有两个Account具有公共数据成员的类,请Balance考虑以下简单代码。

Account a;
...
int withdrawal = 100;
if(a.Balance >= withdrawal)
{
    // No atomic operations in the world can save you from another thread
    // withdrawing some balance here
    a.Balance -= withdrawal
}
else
{
   // Handle error
}

说实话。在现实生活中,原子分配很少足以解决我现实生活中的并发问题。

于 2012-06-20T18:30:16.627 回答
0

这取决于它是如何使用的。其他数据。一个类封装了一个行为,所以一个变量通常没有其他变量几乎是没有意义的。在这种情况下,最好保护(*)属于一起(或整个对象)的数据成员,而不是只保护一个整数。如果你这样做,那么AtomicInteger是不必要的性能损失

(*) 使用常见的线程安全机制:互斥量、信号量、监视器等。

于 2012-06-20T18:04:52.833 回答
0

我猜谷歌看到了 OP 并更新了他们关于这个主题的文档以更清晰:

“AtomicInteger 用于原子递增计数器等应用程序,不能用作 Integer 的替代品。”

https://developer.android.com/reference/java/util/concurrent/atomic/AtomicInteger

于 2020-11-11T01:21:02.500 回答