我的代码类似于以下内容:
class OuterClass
{
private final AtomicInteger count = new AtomicInteger(0);
private class InnerClass extends TimerTask
{
public void run()
{
......
......
incremenetCount();
}
}
public void doSomething()
{
.......
.......
incremenetCount();
}
private void incrementCount()
{
count.incrementAndGet();
}
}
从内部类调用incrementCount
与从外部类中的任何其他函数调用它是一样的,因为同步实际上是在变量count
周围吗?
答案 0 :(得分:5)
从内部类调用incrementAndCount与从外部类中的任何其他函数调用它相同[...]
是的,从内部类调用incrementCount()
与从外部调用incrementCount()
调用相同。
所有非静态内部类都隐含引用封闭类的对象,并且通过此引用将调用incrementCount()
。
(如果您的内部类是静态,故事会有所不同。)
因为同步实际上是在变量计数附近吗?
没关系。无论你是从内部还是从外部类进行调用,都会在同一个对象上调用相同的方法。
答案 1 :(得分:3)
简短的回答是它是安全的。
要理解原因,让我们来看看:
class SomeClass {
private final AtomicInteger count = new AtomicInteger(0);
...
private void incrementCount() {
count.incrementAndGet();
}
}
需要考虑两个问题来确定这是否是线程安全的。
count
的提取是否正确同步?回答是 - 因为count
被声明为final
并且有一条规则说明,一旦构造函数完成,就可以在没有同步的情况下读取final
字段。
incrementAndGet()
方法是否是线程安全的?回答是 - AtomicInteger
类的规范是这样说的。
现在让我们看一下内部类的情况。内部类的实例具有对外部类的实例的隐藏最终引用。所以...
public void run() {
incrementCount();
}
相当于......
private final OuterClass $outer; // initialized by the constructor.
...
public void run() {
$outer.incrementCount();
}
通过上面第1点的推理,incrementCount()
调用本身是线程安全的。而$outer
的获取也是线程安全的,因为它隐含地是final
字段。