java 如何以线程安全的方式更改单例中的静态变量?

i2loujxw  于 2023-08-01  发布在  Java
关注(0)|答案(2)|浏览(128)

我有一个单例类,它有多个静态变量和一个刷新方法来更改它们的值。例如。

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
}

exdqitrt

exdqitrt1#

保护static变量与保护任何其他变量没有什么不同。访问时使用synchronized块。通常情况下,你会在一个final锁对象上使用synchronize,该对象与你试图保护的变量在同一作用域中声明,并且具有相同的范围。例如;

static FooType foo;
static BarType bar;
static BazType baz;

// Only access foo, bar, and baz from within synchronized(lock) {...}.
final static Object lock = new Object();

字符串
如果您正在使用某种复杂的技巧 *,而synchronized对您不起作用,那么您可能需要加大赌注,使用ReentrantLock
[3]当然,如果你计划的是如此复杂的事情,那么你可能不会在这里提出你的问题。

toe95027

toe950272#

现在我打算简单地使用refresh更新对主类中对象的引用。在容器类的Singleton类中为对象使用volatile就足够了,还是需要显式的AtomicReference?
将字段放入一个 Package 器不可变对象中是个好主意。然后每个线程都看到一个完整构造的 Package 器对象。然而,竞争条件是它们可能看到先前的 Package 器对象或新刷新的 Package 器。如果每个线程都必须看到最新的版本,那么你应该使用AtomicReference或者将static Wrapper字段设置为volatile,这样任何更新都会立即发布,并且任何对 Package 器的访问都会看到最新的刷新版本。通常,volatile内存屏障的成本足够低,以至于无法检测到。小心过早的优化。
但是,如果适合您的应用程序,您也可以允许延迟刷新。如果你的线程跨越了其他的内存障碍,或者如果它们有缓存更新硬件,那么它们将在某个时候获得新的 Package 器对象,只是不能保证有多快。如果线程经常引用此 Package 器对象,则可能需要此选项。
因此,如果它是关键逻辑,那么支付AtomicReference,但如果它是信息或更新超级频繁的东西,那么懒惰更新可能是足够的。

相关问题