【发布时间】:2011-07-25 12:16:55
【问题描述】:
我在限制对方法的并发访问时遇到问题。我有一个方法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 更新(如果需要)或等待其他线程离开同步块(这会导致小延迟)。
如果方法不是static,那么我有一个问题,因为同步方法只对线程正在使用的当前实例起作用,所以这不起作用。同步的方法也不起作用,似乎锁是特定于实例的而不是特定于类的。
另一种解决方案可能是拥有一个避免创建多个实例的 Singleton,然后使用单个同步的非静态类,但我不太喜欢这种解决方案。
其他信息:
stringNeedRenewal() 虽然必须从数据库中读取,但并不太贵。 renewString() 反而很贵,需要从数据库上的几个表中读取才能最终得出答案。 String 需要任意更新,但这并不经常发生(从每小时一次到每周一次)。
@forsvarir 让我思考……我认为他/她是对的。 return getString(); 必须在同步方法中。乍一看,它似乎可以脱离它,因此线程将能够同时读取它,但是如果一个线程停止运行同时调用getString(),而其他线程部分执行renewString(),会发生什么?我们可能会遇到这种情况(假设一个处理器):
- 线程 1 开始
getString()。操作系统 开始将字节复制到内存中 被退回。 线程 1 在完成复制之前被操作系统停止。
线程 2 进入同步 阻止并启动
renewString(), 把原来的String改成 记忆。- 线程 1 重新获得控制权
并使用 a 完成
getString损坏的String!!所以它复制了一个 旧字符串的一部分和另一个 从新的。
在同步块中进行读取会使一切变得非常缓慢,因为线程只能一个一个地访问它。
正如@Jeremy Heiler 所指出的,这是一个缓存的抽象问题。如果缓存是旧的,请更新它。如果没有,请使用它。最好更清楚地描绘这样的问题而不是单个String(或者想象有2个字符串而不是一个)。那么如果有人在读的同时有人在修改缓存会怎样呢?
【问题讨论】:
标签: java concurrency static synchronized