有没有理由不总是使用AtomicInteger作为数据成员?
在像Android这样的multithreading环境中,一个简单的int
变量可能被多个线程操纵,在哪种情况下仍然有理由使用int
作为数据成员?
作为局部变量的int
,仅限于具有独占访问权限的方法的范围(因此开始和完成修改它总是在同一个线程中),在性能方面完全有意义。
但作为数据成员,即使由访问器包装,它也可能遇到众所周知的并发交错修改问题。
所以看起来“玩得安全”可以全面使用AtomicInteger
。 但这似乎非常低效。
你能带一个线程安全的int
数据成员用法的例子吗?
有没有理由不总是使用AtomicInteger作为数据成员?
是的,有充分的理由不总是使用AtomicInteger
。 AtomicInteger
可以至少慢一个数量级(可能更多),因为volatile
构造比一个局部int
和其他Unsafe
构造用于设置/获取底层int
值。 volatile
表示每次访问AtomicInteger
都会跨越内存屏障,这会导致有问题的处理器上的缓存内存冲洗。
此外,仅仅因为您将所有字段设置为AtomicInteger
并不能在访问多个字段时保护您免受竞争条件的影响。 对于何时使用volatile
, synchronized
和Atomic*
类做出正确的决定没有任何替代品。
例如,如果您希望在线程程序中以可靠的方式访问类中的两个字段,那么您将执行以下操作:
synchronized (someObject) { someObject.count++; someObject.total += someObject.count; }
如果这两个成员都使用AtomicInteger
那么您将访问volatile
两次,因此跨越2个内存屏障而不是1。此外,分配比AtomicInteger
的Unsafe
操作更快。 此外,由于两个操作的数据竞争条件(与上面的synchronized
块相反),您可能无法获得正确的total
。
你能带一个线程安全的int数据成员用法的例子吗?
除了将其标记为volatile
或使用AtomicInteger
之外,没有任何机制可用于线程安全的int
数据成员。 没有神奇的方法可以在所有字段上绘制线程安全性。 如果有,那么线程编程将很容易。 挑战在于找到放置synchronized
块的正确位置。 找到应标记为volatile
的正确字段。 找到合适的地方使用AtomicInteger
和朋友。
如果你有一个有效的不可变的东西,你可以逃避不以计算为代价来确保同步。 一个例子是hashCode
int hash = 0; public int hashCode(){ if(hash == 0){ hash = calculateHashCode(); //needs to always be the same for each Object } return hash; }
这里明显的权衡是对同一个哈希值进行多次计算的可能性,但是如果备选方案是一个可能具有更糟糕影响的synchronized
哈希代码。
这在技术上是线程安全的,虽然冗余。
这取决于它是如何使用的。 其他数据。 类封装了一个行为,因此如果没有其他变量,变量通常几乎没有意义。 在这种情况下,保护(*)属于一起的数据成员(或整个对象)可能更好,而不仅仅是一个整数。 如果你这样做,那么AtomicInteger
是一个不必要的性能AtomicInteger
(*)使用通用线程安全机制:互斥,信号量,监视器等。
线程安全不仅与primefacesint赋值有关,还需要仔细设计锁定模式以获得代码的一致性。
如果您有两个具有公共数据名称的Account
类,请考虑以下简单代码。
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 }
坦率地说。 在现实生活中,拥有primefaces作业很少能够解决我的现实生活并发问题。