我有一个单例类,它有多个静态变量和一个刷新方法来更改它们的值。例如。
Class Singleton {
@Getter(AccessLevel.Protected)
private static Immutable vara;
@Getter(AccessLevel.Protected)
private static Immutable varb;
@Getter(AccessLevel.Protected)
private static Immutable varc;
public void refresh() {
//refreshes the values of vara, varb, varc;
}
字符串
在访问变量的服务类中访问这个单例类。我怎样才能使刷新线程的过程安全,使刷新不会发生在两次访问之间?例如->access vara -> refresh -> access varb。
我的应用程序部署在Tomcat上。
更新:按照注解中的建议,我修改了类,使其在单个容器类中包含所有三个引用变量,并使它们不可变。现在我打算简单地使用refresh更新对主类中对象的引用。在容器类的Singleton类中为对象使用volatile就足够了,还是需要显式的AtomicReference?新职业:
Class Singleton {
private Container container;//contains immutable invariants
public Container getContainer() {
return this.container;
}
void init() {
// sets initial values for the container object
}
public void refresh() {
// updates the container reference
}
型
2条答案
按热度按时间exdqitrt1#
保护
static
变量与保护任何其他变量没有什么不同。访问时使用synchronized
块。通常情况下,你会在一个final
锁对象上使用synchronize
,该对象与你试图保护的变量在同一作用域中声明,并且具有相同的范围。例如;字符串
如果您正在使用某种复杂的技巧 *,而
synchronized
对您不起作用,那么您可能需要加大赌注,使用ReentrantLock
。[3]当然,如果你计划的是如此复杂的事情,那么你可能不会在这里提出你的问题。
toe950272#
现在我打算简单地使用refresh更新对主类中对象的引用。在容器类的Singleton类中为对象使用volatile就足够了,还是需要显式的AtomicReference?
将字段放入一个 Package 器不可变对象中是个好主意。然后每个线程都看到一个完整构造的 Package 器对象。然而,竞争条件是它们可能看到先前的 Package 器对象或新刷新的 Package 器。如果每个线程都必须看到最新的版本,那么你应该使用
AtomicReference
或者将static Wrapper
字段设置为volatile
,这样任何更新都会立即发布,并且任何对 Package 器的访问都会看到最新的刷新版本。通常,volatile
内存屏障的成本足够低,以至于无法检测到。小心过早的优化。但是,如果适合您的应用程序,您也可以允许延迟刷新。如果你的线程跨越了其他的内存障碍,或者如果它们有缓存更新硬件,那么它们将在某个时候获得新的 Package 器对象,只是不能保证有多快。如果线程经常引用此 Package 器对象,则可能需要此选项。
因此,如果它是关键逻辑,那么支付
AtomicReference
,但如果它是信息或更新超级频繁的东西,那么懒惰更新可能是足够的。