Java线程安全类,参数每小时刷新一次

Java线程安全类,参数每小时刷新一次,java,multithreading,Java,Multithreading,我有以下课程: public class TextSuggester { private Suggester suggester; public TextSuggester() { createSuggester(); public void refresh() { createSuggester(); } private void createSuggester() { suggester = ne

我有以下课程:

public class TextSuggester {

    private Suggester suggester;

    public TextSuggester() {
        createSuggester();

    public void refresh() {
        createSuggester();
    }

    private void createSuggester() {
        suggester = new Suggester(File file); // expensive operation
    }    

    public String lookup(String text) {
        return suggester.lookup(text);
    }

}
将从多个线程访问
lookup
方法。
refresh
方法将每小时调用一次,而且代价高昂(需要很长时间)。我的问题是:

1) 这种设计是线程安全的吗

2) 如果在调用
refresh
之后,但在
refresh
返回之前,另一个线程调用了
lookup
方法,它会使用“old”suggester对象进行查找吗


如果这两个问题的答案都是否定的,那么我如何实现我所需要的呢?本质上,我希望在创建新的建议时使用“旧的”建议

您当前的代码不是线程安全的。没有任何东西可以保证
查找
中线程A看到的
建议者
的值与
创建建议者
中线程B分配的
建议者
的值相同

您需要做的是添加某种同步,以便所有更改都可见。由于您的所有方法基本上都只是与
suggester
进行交互,因此您的before-ordering应该与该字段相关<代码>易失性是一个选项。这是另一个

所以

private volatile Suggester suggester; // with standard field access and assignment

private final AtomicReference suggesterRef;//在构造函数中正确初始化
...
私有void createSuggester(){
set(新建议者(文件));
}   

在实际调用
set
之前,调用
get
(在
lookup
中)的所有其他线程都将看到以前分配的值。

现在没有任何线程是安全的。使您的字段
不稳定
,并懒洋洋地执行新任务。@SotiriosDelimanolis感谢您的快速响应。您可以详细说明或发布一个答案吗?使您的
建议者
字段
易变
将确保任何读取该字段的线程都会看到另一个线程写入该字段的最新值。如果在调用
lookup
时正在创建一个新的
Suggester
,那么调用线程将使用最近编写的一个(上次
refresh
调用时创建的
Suggester
)。您还在注释中提到要与“volatile”一起使用的延迟加载。这也有必要吗?或者仅仅让Suggester变得易变就足够了?@stepanian延迟加载指的是只有在新的
Suggester
对象完全初始化时才会设置变量或
原子引用。所以“volatile”关键字就是完成延迟加载的原因,对吗?另外,出于好奇,如果不使用“volatile”并且线程在另一个线程完成之前尝试访问“suggester”,会发生什么?如果不是旧物体,那又怎样?它崩溃了吗?@stepanian分配给它的任务是这样的。您的
TextSuggester
本身就像是对
TextSuggester
的引用。如果未使用
volatile
,JVM将不会崩溃。但它可以返回旧值或新值。这是Java内存模型的一部分,在不使用volatile的情况下,有许多可能的程序顺序。您可以阅读有关
volatile
的更多信息。抱歉,最后一个问题:如果线程非常短暂,并且不要求它们访问最新的suggester对象,那么我是否仍然需要使用“volatile”?稍后创建的线程最终会访问最近的suggester对象吗?谢谢
private final AtomicReference<Suggester> suggesterRef; // initialized correctly in constructor
...
private void createSuggester() {
    suggesterRef.set(new Suggester(File file));
}