如果我把它复制到另一个变量并尝试改变它,那么变量是否会变化?

时间:2015-01-22 18:06:00

标签: java android multithreading thread-safety volatile

我有一个Android应用程序对象(虽然这纯粹是我认为的java问题),如下所示

我想了解我使用volatile的方式是否正确,我已将Application中的appData定义为volatile,这是否自动保证AppData对象内的所有变量(每个变量都是像数组一样的复杂对象本身)也是不稳定的,或者我是否需要明确地使它们变得像我所做的那样不稳定

另外,正如我在标记为QUESTION的注释中提到的那样,将新变量X等同于一个volatile变量也会使X变得不稳定?

public class App extends Application{
    private volatile static AppData appData;

    public void fetchMePageInfo(long idOfUserIfNotForSelf) {

        RestService.getMePageInfo(new Callback<MePageInfo>() {          // RestService is just another class that calls Web server, and has static method getMepageInfo

            @Override
            public void success(MePageInfo newMePageInfo, Response response) {
                // for successful server request, store the newly fetched me page in array
                // and set ref to both self me page ref = me page to be displayed = new object,

                ArrayList<MePageInfo> mPageInfoList = appData.getMePageInfoList();      
                // QUESTION : AppData is volatile, but does that mean mPageInfoList is also threadsafe?

                MePageInfo selfRef = appData.getUserMePageInfo();
                if (selfRef != null) {
                    // if me page exists already, additionally remove the existing me page first
                    mPageInfoList.remove(selfRef);
                }
                mPageInfoList.add(newMePageInfo);

                appData.setUserMePageInfo(newMePageInfo);  // does not automatically call change listeners

            }


        });
    }




}


public class AppData {

    /**
    this has the MePageInfo objects of the various other users that the logged in user might go to 
     for quick fetch, instead of calling server each time
    **/
    volatile ArrayList<MePageInfo> mePageInfoList = new ArrayList<MePageInfo>();

    // region self Me page info data
    /**
     * the MePageInfo for the logged in user, this is null initially and is filled by FetchGenericMePageInfo for the user
     */

    volatile MePageInfo userMePageInfo = null;

}

3 个答案:

答案 0 :(得分:1)

易失性和线程安全不是一回事。 volatile向您保证

  1. 写入volatile变量并随后读取此变量会在两个线程之间建立一个先发生的关系。

  2. 此特定变量的所有读写都是原子的。

  3. 这就是它的全部功能。因此,如果您将volatile变量的值分配给另一个变量,则不会使其成为volatile。线程安全的概念更复杂,变量为volatile的事实并不意味着即使这个变量本身也是线程安全的。

答案 1 :(得分:1)

存在&#34;不稳定&#34;是变量的属性,而不是它引用的对象的属性。所以(假设我们在这里讨论参考变量,而不是原语),标记变量&#34; volatile&#34;不会使对象线程安全。并且您可能有一个易失性变量和一个非易失性变量,它们都引用同一个对象。

因此,当您将引用变量标记为&#34; volatile&#34;时,您说其他线程可能会使变量引用不同的对象。你并不是说其他​​线程可能会改变它引用的对象。

因此,为了回答您的第一个问题,对象内的字段的波动性完全独立于引用该对象的任何变量的波动性。回答第二个问题,变量不能通过引用易失性对象而变得易变。

答案 2 :(得分:0)

  

这会自动保证AppData对象中的所有变量(每个变量都是数组等复杂对象)

没有。做类似的事情:

appData = new AppData();
appData.mePageInfoList = new ArrayList<>();

不是线程安全的。对mePageInfoList的写入可以不按顺序读取。所以为了回答你的问题,没有人会知道何时会读到AppData内的字段。

  

我是否需要像我一样明确地使它们变得不稳定

是的,但即便如此,你也不一定安全。例如,ArrayList不是线程安全的,因此分配给mePageInfoList将是线程安全的,但任何后来的集合变异都将存在风险。

  

将一个新变量X等同于一个volatile变量也会使X变得不稳定吗?

不完全确定你在问什么,你能举个例子吗?