gpt4 book ai didi

java - 限制对方法的并发访问

转载 作者:行者123 更新时间:2023-11-29 06:14:51 25 4
gpt4 key购买 nike

我在限制对方法的并发访问方面遇到了问题。我有一个方法 MyService 可以从很多地方多次调用。此方法必须返回一个 String,它应该根据某些规则进行更新。为此,我有一个 updatedString 类。在获取 String 之前,它会确保 String 已更新,如果没有,则更新它。许多线程可以同时读取 String 但只有一个线程应该同时更新 String 如果它已过期。

public final class updatedString {

private static final String UPstring;
private static final Object lock = new Object();

public static String getUpdatedString(){
synchronized(lock){
if(stringNeedRenewal()){
renewString();
}
}
return getString();
}

...

这很好用。如果我有 7 个线程获取字符串,它保证在必要时只有一个线程正在更新字符串。

我的问题是,让所有这些static 是个好主意吗?为什么不呢?快吗?有更好的方法吗?

我看过这样的帖子: What Cases Require Synchronized Method Access in Java?这表明静态可变变量不是一个好主意,静态类也不是。但是我看不到代码中有任何死锁或更好的有效解决方案。只是有些线程必须等到 String 更新(如有必要)或等待其他线程离开同步块(synchronized block)(这会导致小延迟)。

如果该方法不是static,那么我就会遇到问题,因为这将不起作用,因为同步方法仅对线程正在使用的当前实例起作用。 synchronized 方法也不管用,好像锁是instance-specific 而不是class-specific。另一种解决方案可能是拥有一个避免创建多个实例的单例,然后使用单个同步非静态类,但我不太喜欢这种解决方案。

附加信息:

stringNeedRenewal() 虽然必须从数据库中读取,但并不昂贵。 renewString() 反而是非常昂贵的,必须从数据库中读取多个表才能最终得出答案。 String 需要任意更新,但这种情况不会经常发生(从每小时一次到每周一次)。

@forsvarir 让我思考...我认为他/她是对的。 return getString(); 必须在同步方法内。乍一看,它似乎可以脱离它,因此线程将能够并发读取它,但是如果一个线程在调用 getString() 时停止运行并且其他线程部分执行 更新字符串()?我们可能会遇到这种情况(假设只有一个处理器):

  1. 线程 1 启动 getString()。操作系统开始将字节复制到内存中将被退回。
  2. 线程 1 在完成复制之前被操作系统停止。

  3. 线程 2 进入同步阻止并启动 renewString(),改变原来的 String 在内存。

  4. 线程 1 重新获得控制权并使用一个完成 getString损坏的 String!!所以它复制了一个从旧字符串和另一个字符串中分离出来来自新的。

在同步块(synchronized block)中进行读取会使一切变得非常缓慢,因为线程只能一个接一个地访问它。

正如@Jeremy Heiler 所指出的,这是缓存的抽象问题。如果缓存是旧的,更新它。如果没有,请使用它。像这样描述问题比单个 String 更好更清楚(或者想象有 2 个字符串而不是一个)。那么,如果有人正在读取的同时有人正在修改缓存,会发生什么情况呢?

最佳答案

首先,您可以删除锁和同步块(synchronized block)并简单地使用:

public static synchronized String getUpdatedString(){
if(stringNeedRenewal()){
renewString();
}
return getString();
}

这在 UpdatedString.class 对象上同步。

您可以做的另一件事是使用双重检查锁定来防止不必要的等待。将字符串声明为 volatile 并且:

public static String getUpdatedString(){
if(stringNeedRenewal()){
synchronized(lock) {
if(stringNeedRenewal()){
renewString();
}
}
}
return getString();
}

然后,是否使用静态 - 似乎它应该是静态的,因为您想在没有任何特定实例的情况下调用它。

关于java - 限制对方法的并发访问,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5476825/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com