Tim*_*ler 4 java synchronization double-checked-locking
我正在使用java大约一个月,而且我一般都是编程的业余爱好者,所以如果我出错了,请随时纠正我.也许我会提供一些过多的细节,但我现在很困惑,我无法决定什么是重要的.
所以,我一直在开发多线程客户端 - 服务器应用程序.所有线程都使用相同的对象,其中存储了某些配置值和共享记录器; 此对象在服务器线程中初始化,然后作为参数传递给客户端线程类构造函数.首先,假设当服务器启动时,该对象的字段只更改一次,因此并发访问无需担心,但现在需要在修改时从配置文件中重新读取某些配置值,而不必重启服务器.
在一些研究之后想到的第一个想法是创建一个同步方法,当请求类中的某些值时将调用该方法,并且如果我们的配置文件自上次访问后发生更改则会重新读取这些值,否则会立即返回,如这个:
<This code is inside "config" class, instance of which is shared between threads>
private static long lastModified;
private static File configFile;
public class ChangingVariableSet
{
<changing variables go here>
}
private synchronized void ReReadConfig
{
long tempLastMod = configFile.lastModified();
if(lastModified == tempLastMod)
return;
<reread values here>
lastModified = tempLastMod;
}
public ChangingVariableSet GetValues()
{
ReReadConfig();
<return necessary values>
}
Run Code Online (Sandbox Code Playgroud)
(上面的代码没有经过测试,我只是希望得到一般的想法).
但我只是不喜欢堵的想法每一次请求的值,因为这似乎昂贵,以及我的应用程序有可能成为相当高负荷,有很多在未来线程的可能性.所以我有一个"好"的想法 - 在锁定之前检查文件是否被修改,然后再次在锁定方法内部,以避免在任何可能的情况下锁定:
public ChangingVariableSet GetValues()
{
if(lastModified == configFile.lastModified())
ReReadConfig();
<return necessary values>
}
Run Code Online (Sandbox Code Playgroud)
十分钟后,我学会了它被称为双重检查锁定,另外十分钟后我的世界在读完这篇文章后崩溃了两次:第一次当我学会它时,据说由于内部CPU缓存而无法工作,第二次当我读到长时间操作时/ float类型不是原子的.或者它是否会起作用,因为不涉及对象创建?并且,由于long上的操作是非原子的,将"lastModified"声明为volatile是否足够?如果可能的话,我更愿意正确解释它为什么会/不会起作用.先感谢您.
PS:我知道类似的问题已经回答了几次,也许最好停止挑剔和同步整个"getValue"方法而不是"ReReadConfig",但我正在努力学习更多关于线程安全编程和在我自己的代码中查看陷阱以避免将来出现类似情况.我也为任何可能的语法和拼写错误道歉,我不太懂英语.
编辑:首先,我修改了最后一个"if"条款中的拼写错误.第二 - 警告,上面的代码不是线程安全的,不要使用它!在方法中
public ChangingVariableSet GetValues()
{
if(lastModified == configFile.lastModified())
ReReadConfig();
<return necessary values>
}
Run Code Online (Sandbox Code Playgroud)
如果文件是在时间跨度如果检查和值返回之前,线程A开始返回值,导致对必要的数据的危险部分改变线程B可以开始ReReadConfig之间更新.在没有过多阻塞的情况下执行我需要的正确方法似乎是使用ReentrantReadWriteLock,但是,我仍然希望使用双重检查以避免过多(并且昂贵的,文件被假定为大型XML)配置重新读取:
<...>
private static final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
private static final Lock read = readWriteLock.readLock();
private static final Lock write = readWriteLock.writeLock();
private void ReReadConfig
{
write.lock();
long tempLastMod = configFile.lastModified();
if(lastModified == tempLastMod)
return;
<reread values here>
lastModified = tempLastMod;
write.release();
}
public ChangingVariableSet GetValues()
{
if(lastModified == configFile.lastModified())
ReReadConfig();
read.lock();
<get necessary values>
read.release();
<return necessary values>
}
Run Code Online (Sandbox Code Playgroud)
现在它至少看起来是线程安全的,但问题仍然是开放的,取决于检查时的volatile"lastModified"变量:我已经读过某些地方,volatile变量无法保证非原子操作的任何内容,而"long"类型读取/写是非原子的.
| 归档时间: |
|
| 查看次数: |
390 次 |
| 最近记录: |