简体   繁体   English

声明对象引用在Java中是易失的?

[英]Declaring object reference as volatile in Java?

I have a Spring bean class that look similar to the following: 我有一个看起来类似于以下内容的Spring bean类:

@Component
public class Foo{

    private Config conf;

    @PostConstruct
    public void init(){
        conf = ConfigFileLoader.loadConfigFromFile();
    }

    public Config getConfig(){
        return conf;
    }

    public void updateConfig(){
        conf = ConfigFileLoader.loadConfigFromFile();
    } 

}

ConfigFileLoader.loadConfigFromFile() reads configuration from file and returns a new Config object. ConfigFileLoader.loadConfigFromFile()从文件读取配置,并返回一个新的Config对象。

There are two types of threads: 有两种类型的线程:

  • Updater thread: 更新程序线程:
    • there is only one 只有一个
    • it calls updateConfig periodically (when it detects changes on the configuration file) 它定期调用updateConfig(当它检测到配置文件上的更改时)
  • Reader thread: 读者线程:
    • multiple threads are calling getConfig using the Config object for execution. 多个线程正在使用Config对象调用getConfig来执行。
    • does not care if it receives a stale Config object instance for current execution as long as eventually reader threads start getting an up to date Config object. 只要最终读取器线程开始获取最新的Config对象,它就不会为当前执行而收到过时的Config对象实例。

My question is this, should i mark the private conf field as volatile or maybe add some kind of synchronisation for conf field? 我的问题是,我应该将私有conf字段标记为volatile还是为conf字段添加某种同步?

My fear is the following scenario: the Updater thread updates the conf reference but the change is never made visible to the reader threads. 我担心的是以下情形:Updater线程更新conf引用,但更改永远不会对读取器线程可见。

Any help or explanation will be appreciated. 任何帮助或解释将不胜感激。

The danger here, whether you use volatile or whether you take @sibnick's suggestion and use a ReaderWriterLock, is that some thread will hold on to its own, private reference to a Config object for an extended period of time: 无论您使用volatile还是采用@sibnick的建议并使用ReaderWriterLock,这里的危险是某些线程将长时间保留其自己的Config对象私有引用:

 Config myConfig = foo.getConfig();
 while (conditionThatWillBeTrueForManyIterations()) {
      doSomethingWith(myConfig);
 }

It is impossible to write code that will not keep its own private reference for some period of time because whatever you do with the Config object, you will be doing it outside of the mutex. 这是不可能的编写代码,将持续的时间,因为无论你用做一段时间自己的私人参考Config的对象,你会互斥之外做。

Even if you only write this: 即使你只写这个:

doSomethingWith(foo.getConfig());

It is possible that some other thread will update the configuration in between the foo.getConfig() call and the doSomethingWith(...) call. 其他一些线程可能会在foo.getConfig()调用与doSomethingWith(...)调用之间更新配置。

Your program will have to be able to cope with that possibility. 您的程序必须能够应对这种可能性。

Volatile = An attempt that other threads see the updated value of the object's state , no guarantee that threads run in synch and in a manner that they do not enter a situation that the screw up other's(thread(s) ) work 易失性=尝试使其他线程看到对象状态的更新值,不保证线程同步运行,并且不保证它们不会进入破坏他人线程工作的情况

Synchronized code by intrinsic locks = An attempt to make sure threads see the updated object state + guarantee that threads work in synch and wait for each other so that there is no interference. 通过内部锁进行的同步代码=尝试确保线程看到更新的对象状态+保证线程同步工作并互相等待,以防止相互干扰。

The load method you have defined here will have the instruction set which is not atomic .It reads the file and updates the Object it is loaded into. 您在此处定义的装入方法将具有非原子的指令集。它将读取文件并更新要装入的对象。

The read and update operations from a single thread have to be done in a single go in a manner that no other thread interferes and try to redo the same. 必须单次完成从单个线程进行的读取和更新操作,而不会受到其他线程的干扰,并尝试重做相同的操作。

Volatile is not a sure shot solution to your issue as your actions are not a single statement /assignment procedure. 不确定性不是解决问题的可靠方法,因为您的操作不是一个单一的声明/分配过程。

Recommendation is to use : intrinsic locks on an object and make read and update method work in synch . 建议使用:对象上的固有锁,并使读取和更新方法同步运行。

public class Foo{

    private Config conf;
    Object lock = new Object();
    @PostConstruct
    public void init(){
        synchronize(lock)
        {
            conf = ConfigFileLoader.loadConfigFromFile();
        }
    }

    public Config getConfig(){
        synchronize(lock)
        {
            return conf;
        }
    }

    public void updateConfig(){
        synchronize(lock)
        {
            conf = ConfigFileLoader.loadConfigFromFile();
        }
    }

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM