【发布时间】:2026-01-20 11:25:01
【问题描述】:
说,我有一个数据对象:
class ValueRef { double value; }
每个数据对象存储在主集合中的位置:
Collection<ValueRef> masterList = ...;
我还有一个作业集合,其中每个作业都有一个本地数据对象集合(其中每个数据对象也出现在masterList):
class Job implements Runnable {
Collection<ValueRef> neededValues = ...;
void run() {
double sum = 0;
for (ValueRef x: neededValues) sum += x;
System.out.println(sum);
}
}
用例:
for (ValueRef x: masterList) { x.value = Math.random(); }用一些作业填充作业队列。
唤醒线程池
等到每个作业都评估完毕
注意:在工作评估期间,所有的值都是不变的。然而,线程可能在过去评估过作业,并保留缓存值。
问题:确保每个线程看到最新值所需的最小同步量是多少?
我理解从监视器/锁定角度同步,我不理解从缓存/刷新角度同步(即,在同步块的进入/退出时内存模型保证了什么)。
对我来说,感觉就像我需要在更新值的线程中同步一次以将新值提交到主内存,并在每个工作线程中同步一次,以刷新缓存以便读取新值。但我不确定如何最好地做到这一点。
我的做法:创建一个全局监控器:static Object guard = new Object(); 然后,在guard 上同步,同时更新主列表。最后,在启动线程池之前,对于池中的每个线程,在一个空块中同步guard。
这真的会导致该线程读取的任何值被完全刷新吗?或者只是在同步块内触及的值?在这种情况下,也许我应该循环读取每个值一次,而不是一个空块?
感谢您的宝贵时间。
编辑:我认为我的问题归结为,一旦我退出同步块,每次第一次读取(在那之后)都会进入主内存吗?不管我同步的是什么?
【问题讨论】:
-
似乎是利用 volatile 关键字的完美场所
-
我只写了一次(实际上是恒定的),但可能会读数百万次。 Volatile 永远不会在本地缓存。如果我每次都创建线程池,那么代码可以在没有同步/易失性的情况下正常工作(因为不存在先前的缓存)。
-
我认为这里不需要 volatile。如果 ValueRef 实际上是不可变的,只需使其实际上是不可变的。使用双。在计划之前为每个作业创建一个新集合,并将其包装在 unmodifiableCollection 中(仅作为提醒)。你预见到什么问题?
-
在作业完成之前是不可变的。然后再次更改值并重新启动作业。
标签: java threadpool synchronize