在像 Android 这样的多线程环境中,一个简单的int
变量可以由多个线程操作,在某些情况下仍然可以使用 anint
作为数据成员吗?
Anint
作为局部变量,仅限于对其具有独占访问权限的方法的范围(因此修改它的开始和结束总是在同一个线程中),在性能方面非常有意义。
但作为数据成员,即使被访问器包装,也会遇到众所周知的并发交错修改问题。
因此,看起来“稳妥行事”,人们可以AtomicInteger
全面使用。但这似乎非常低效。
你能举一个线程安全int
数据成员使用的例子吗?
在像 Android 这样的多线程环境中,一个简单的int
变量可以由多个线程操作,在某些情况下仍然可以使用 anint
作为数据成员吗?
Anint
作为局部变量,仅限于对其具有独占访问权限的方法的范围(因此修改它的开始和结束总是在同一个线程中),在性能方面非常有意义。
但作为数据成员,即使被访问器包装,也会遇到众所周知的并发交错修改问题。
因此,看起来“稳妥行事”,人们可以AtomicInteger
全面使用。但这似乎非常低效。
你能举一个线程安全int
数据成员使用的例子吗?
是否有任何理由不总是使用 AtomicInteger 作为数据成员?
是的,有充分的理由不总是使用AtomicInteger
. 由于构造比本地构造和用于设置/获取基础值 的其他构造,它AtomicInteger
可以至少慢一个数量级(可能更多) 。意味着每次访问时都会跨越内存屏障,这会导致相关处理器上的缓存内存刷新。volatile
int
Unsafe
int
volatile
AtomicInteger
此外,仅仅因为您已将所有字段都设置为,AtomicInteger
并不能在访问多个字段时保护您免受竞争条件的影响。对于何时使用volatile
,synchronized
和Atomic*
类做出正确的决定是无可替代的。
例如,如果您希望在线程程序中以可靠的方式访问一个类中有两个字段,那么您将执行以下操作:
synchronized (someObject) {
someObject.count++;
someObject.total += someObject.count;
}
如果这两个成员都具有,AtomicInteger
那么您将访问两次,因此跨越 2 个内存障碍,而不仅仅是 1 个。此外,分配volatile
比. 此外,由于这两个操作的数据竞争条件(与上面的块相反),您可能无法获得正确的.Unsafe
AtomicInteger
synchronized
total
你能举一个线程安全的 int 数据成员使用的例子吗?
除了制作它之外final
,int
除了标记它volatile
或使用AtomicInteger
. 没有什么神奇的方法可以在所有字段上绘制线程安全。如果有那么线程编程将很容易。挑战在于找到放置synchronized
积木的正确位置。找到应该用 标记的正确字段volatile
。找到合适的地方使用AtomicInteger
和朋友。
如果您有有效的不可变int
s,您可以避免以计算成本为代价不确保同步。一个例子是hashCode
int hash = 0;
public int hashCode(){
if(hash == 0){
hash = calculateHashCode(); //needs to always be the same for each Object
}
return hash;
}
这里明显的权衡是对同一个哈希值进行多次计算的可能性,但如果替代方案是哈希码,则synchronized
可能会产生更糟糕的影响。
这在技术上是线程安全的,尽管是多余的。
线程安全不仅与原子 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
}
说实话。在现实生活中,原子分配很少足以解决我现实生活中的并发问题。
这取决于它是如何使用的。其他数据。一个类封装了一个行为,所以一个变量通常没有其他变量几乎是没有意义的。在这种情况下,最好保护(*)属于一起(或整个对象)的数据成员,而不是只保护一个整数。如果你这样做,那么AtomicInteger
是不必要的性能损失
(*) 使用常见的线程安全机制:互斥量、信号量、监视器等。
我猜谷歌看到了 OP 并更新了他们关于这个主题的文档以更清晰:
“AtomicInteger 用于原子递增计数器等应用程序,不能用作 Integer 的替代品。”
https://developer.android.com/reference/java/util/concurrent/atomic/AtomicInteger