Java中的易失类实例和成员访问

时间:2014-05-29 23:11:13

标签: java multithreading thread-safety volatile

我认为我所做的事情是正确的,但如果不是这样可能会非常糟糕,我真的很想澄清。

代码是尝试表达观点的一个例子,对于任何小错字都很抱歉。

我有以下课程

public class Components
{
    public final String mVar1;
    public final boolean mVar2;

    public Components(String var1, boolean var2)
    {
        mVar1 = mVar1;
        mVar2 = mVar2;
    }
}

如果我创建此类的volatile实例,我相信将此组件的值分配给已创建的内容的地址并且在内存中是线程安全的。

public class Storage
{
    public static volatile Components sComponents = null;
}

因此,无论我是在主线程还是任何其他线程上设置此变量(其中一个集合只是将其指向已创建的对象,而不是创建一个新的),它应该是线程安全的,因为volatile关键字正在对组件引用进行操作,该引用只会更新为指向已存在的对象。

所以,例如

public class ThreadedClass
{
    public ThreadedClass()
    {
        // Create an instance of Components so we have something to copy
        mInitialComponents = new Components("My String", false);

        // Spin off a thread
        create_a_new_thread( threadEntryPoint );
    }

    // This function is called every frame on the main thread
    public void update()
    {
        // If we have our components, print them out
        if (Storage.sComponents != null)
        {
            print(sComponents.mVar1);
            print(sComponents.mVar2);
        }
    }

    private Components mInitialComponents = null;

    private void threadEntryPoint()
    {
        // Just sleep for a bit so update gets called a few times
        sleep(3000);

        // Set our components
        Storage.sComponents = mInitialComponents;
    }
}

(在现实世界的代码中,mInitialComponents是通过同步函数创建和访问的,因此访问原始对象是线程安全的。)

所以,我的问题是,当在main或任何其他线程上调用update时,一旦将Storage.sComponents设置为threadEntryPoint中的现有对象,它是否只是更新对象引用,因此该对象将保证是每当我们检查null时就完成。

或者是否可以正确分配某些内部成员或没有内部成员。

由于

2 个答案:

答案 0 :(得分:1)

您的更新方法不是线程安全的,可能会抛出空指针异常。这可以通过将其更改为:

来解决
// This function is called every frame on the main thread
public void update()
{
    final Components components = Storage.sComponents;
    // If we have our components, print them out
    if (components != null)
    {
        print(components.mVar1);
        print(components.mVar2);
    }
}

组件中的内部值可以安全使用,因为它们是最终的。这假设您不会从其构造函数中泄漏对Components实例的引用。

答案 1 :(得分:1)

可以安全地假设,如果components不为null,则其成员变量已正确初始化。根据Java虚拟机规范,通过对new返回的对象的引用进行的任何访问都可以保证看到该对象中任何final字段的完全初始化版本。请参阅JVM规范,第17.5章。