int
变量可能会被多个线程操作。在某些情况下,仍然有正当理由将int
用作数据成员吗?对于限定在方法范围内、只能由一个线程独占访问(因此修改始终在同一线程中进行)的局部变量来说,
int
在性能上是完全合理的。但是作为数据成员,即使被封装在访问器中,它也可能遇到众所周知的并发交错修改问题。
因此,看起来“玩得安全”就可以在整个程序中使用
AtomicInteger
。但是这似乎非常低效。你能举一个线程安全的
int
数据成员使用的例子吗?int
变量可能会被多个线程操作。在某些情况下,仍然有正当理由将int
用作数据成员吗?int
在性能上是完全合理的。AtomicInteger
。但是这似乎非常低效。int
数据成员使用的例子吗?是否总是使用AtomicInteger作为数据成员有正当理由吗?
是的,有很好的理由不总是使用AtomicInteger
。由于volatile
构造和其他用于设置/获取基础int
值的Unsafe
构造,AtomicInteger
可能比本地int
慢至少一个数量级(可能更多)。volatile
意味着每次访问AtomicInteger
时都会跨越内存屏障,这会导致在相关处理器上进行高速缓存刷新。
此外,仅仅因为您已将所有字段设置为AtomicInteger
并不意味着在多个字段被访问时就可以保护您免受竞态条件的影响。没有任何替代方案可以取代对何时使用volatile
、synchronized
和Atomic*
类做出明智决策。
例如,如果您想要以可靠的方式访问类中的两个字段,则可以执行以下操作:
synchronized (someObject) {
someObject.count++;
someObject.total += someObject.count;
}
AtomicInteger
,那么您将访问volatile
两次,因此跨越了2个内存屏障而不是1个。此外,与AtomicInteger
内部的Unsafe
操作相比,分配速度更快。另外,由于存在数据竞争条件(与上面的synchronized
块相反),您可能无法获得正确的total
值。
除了将其标记为您能举个线程安全的int数据成员的使用例子吗?
final
之外,没有机制可以使int
数据成员线程安全,除非将其标记为volatile
或使用AtomicInteger
。并没有一种神奇的方法可以使所有字段都具有线程安全性。如果有的话,线程编程将变得容易。挑战在于找到适当的位置来放置您的synchronized
块,找到应该用volatile
标记的正确字段,以及找到使用AtomicInteger
和其他类的正确位置。int
数据成员的类的线程安全性? - ef2011synchronized
,我再问一个相关的问题:我敢说我在某个地方看到使用注释@Synchronized
比synchronized
更优秀。这是真的吗?你能在回答中提到吗? - ef2011如果您有不可变的int
,则可以在不确保同步的情况下进行计算,这样可以节省成本。一个例子是hashCode
int hash = 0;
public int hashCode(){
if(hash == 0){
hash = calculateHashCode(); //needs to always be the same for each Object
}
return hash;
}
这里明显的权衡是对于相同哈希值可能存在多次计算的可能性,但如果选择一个synchronized
的hashCode,其影响可能更为严重。
尽管多余,但这在技术上是线程安全的。
calculateHashCode
需要为每个对象返回相同的值。 - John VintString
不是线程安全的吗?那个类执行非常相似的操作。 - John Vinthttps://developer.android.com/reference/java/util/concurrent/atomic/AtomicInteger
这取决于它与其他数据的使用方式。类封装了一种行为,因此一个变量通常没有其他变量就几乎没有意义。在这种情况下,保护属于一起的数据成员(或整个对象)可能比仅保护一个整数更好。如果您这样做,那么AtomicInteger
是不必要的性能损失。
(*) 使用常见的线程安全机制:互斥锁、信号量、监视器等。
线程安全不仅仅是关于原子整数赋值,您需要仔细设计锁定模式以在代码中获得一致性。
如果您有两个具有公共数据成员Balance
的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
}
++
也不是原子性的。 - ef2011