Outer的两个实例是否可能通过在TASK_UPDATER上调用doSomething而以某种方式干扰彼此?
答案是“视情况而定”。任何时候你有多个线程共享相同的对象实例,你可能会遇到并发问题。在你的情况下,你有多个实例Outer
共享相同的static
TaskUpdater
实例。这本身不是问题,但如果TaskUpdater
有任何字段,它们将由线程共享。如果线程以任何方式对这些字段进行了任何更改,那么数据同步需要发生,并且可能会阻止关键代码段。如果TaskUpdater
是只有读取和操作Task
的说法,这似乎是每个Outer
实例,那就没有问题了。
例如,你可以有一个任务更新,如:。
public static final TaskUpdater TASK_UPDATER = new TaskUpdater() {
public void doSomething(Task task) {
int total = 0;
for (Job job : task.getJobs() {
total += job.getSize();
}
task.setTotalSize(total);
}
};
在这种情况下,任务只改变Task
例如在通过它可以使用局部变量不会有问题,因为这些都是在堆栈,现在在线程之间共享。这是线程安全的。
但是考虑此更新:
public static final TaskUpdater TASK_UPDATER = new TaskUpdater() {
private long total = 0;
public void doSomething(Task task) {
for (Job job : task.getJobs() {
// race condition and memory synchronization issues here
total += job.getSize();
}
}
public long getTotal() {
return total;
}
};
在这种情况下,两个线程都将在碎片TaskUpdater
更新同一total
领域。这不是线程安全的,因为你的竞争条件是+=
(因为它是3个操作:get,plus,set)以及内存同步问题。一个线程可能有total
这是5,它递增至6缓存的版本,但另一个线程已经增加的total
其缓存的版本,以10
当线程份额公共字段你需要保护这些业务而发愁关于互斥访问和内存发布的同步。在这种情况下,使total
成为AtomicLong
将是有序的。
private AtomicLong total = new AtomicLong(0);
...
total.addAndGet(job.getSize());
AtomicLong
包装了一个volatile long
所以内存被适当地发布到所有线程,它有代码,不会原子测试/设置操作从而消除了竞争条件。
您能否详细说明您观察到的奇怪行为? – Rainbolt
鉴于'doSomething()'不同步,当然,两个线程可以同时执行'doSomething()'。它能引起“干扰”吗?我们怎么能看到这个类的一行代码? –
每个线程都在处理它自己的'Task'实例?在'Outer'中是否有任何字段被修改? – Gray