English 中文(简体)
我应该同步一个静态波动变量吗?
原标题:Should I synchronize a static volatile variable?

在这个问题上有几个问题,但多数人绕过这个问题,因为它不是问题的本意。

如果我的班级出现静态波动

private static volatile MyObj obj = null;

以我以下的方法:

public MyObj getMyObj() {
    if (obj == null) {
        obj = new MyObj();// costly initialisation
    }
    return obj;
}

我是否需要同步以确保只给字段写一个线索, 或者任何写作会立即被其他编辑看到, 以评价 obj = null 的条件吗?

换句话说: 波动是否让你不得不同步访问 来写一个静态变量?

最佳回答

您确实需要锁定 somes 的排序, 以确保只有一条线索写到字段。 无论是否波动, 两个线索都可以“ 查看”, aobj 是空的, 然后都以您当前的代码开始初始化 。

我个人选择三种选择之一:

  • 初始化类负载( 知道这将是懒惰的, 但不像等待 < code> getMyObj < /code > 先调用) :

    private static final MyObj obj = new MyObj();
    
  • 使用无条件锁定 :

    private static MyObj obj;
    private static final Object objLock = new Object();
    
    public static MyObj getMyObj() {
        synchronized(objLock) {
            if (obj == null) {
                obj = new MyObj();
            }
            return obj;
        }
    }
    
  • 使用嵌巢类懒惰方式 :

    public static MyObj getMyObj() {
        return MyObjHolder.obj;
    }
    
    private static class MyObjHolder {
        static final MyObj obj = new MyObj();
    }
    
问题回答

是的, 您应该绝对同步化( 或者使用像 < a href=" http:// en. wikipedia. org/ wiki/ Intiatalization- on- demand_ desistr_ idiom" rel = “ nofollow” @ em > Singleton Holder idiom 这样的更好的语句 。 否则, 您将面临多个线条对对象进行多次初始化的风险( 然后再使用不同实例 ) 。

想想这样的一系列事件:

  1. Thread A enters getMyObj() and sees that obj == null
  2. Thread B enters getMyObj() and sees that obj == null
  3. Thread A constructs a new MyObj() - let s call it objA
  4. Thread B constructs a new MyObj() - let s call it objB
  5. Thread A assigns objA to obj
  6. Thread B assigns objB to obj (which is not null anymore at this point, so the reference to objA, assigned by Thread A, is overwritten)
  7. Thread A exits getMyObj() and starts to use objA
  8. Thread B exits getMyObj() and starts to use objB

这种情景可能随任何几条线而发生。 请注意,虽然为了简单起见,我假设在真实的多读环境事件1-2、3-4和/或7-8中,我假设了严格的事件顺序,但时间上可以部分或完全重叠,而不会改变最终结果。

持单人名词的一个例子:

public class Something {
    private Something() {
    }

    private static class LazyHolder {
        public static final Something INSTANCE = new Something();
    }

    public static Something getInstance() {
        return LazyHolder.INSTANCE;
    }
}

由于 inSTance final 。 Java 内存模型保证,在装入包含类时, final 字段初始化,并正确显示于任何数条线条上。由于 LazyHolder 私人的 ,且仅由 getInstance () 引用,因此只有在首先调用 getInstance () 时才被装入。 此时, instance < () 在背景中初始化,并由JVM 安全发布。

否,您仍然需要同步访问。 volatile 允许用一条线对变量进行修改,以便其他线索能看到。

想象以下执行流程( 假设两条T1 & amp; T2) :

  1. obj is null initally.
  2. T1: if (obj == null): YES
  3. T2: if (obj == null): YES
  4. T1: creates a new instance of MyObj and assign it to obj
  5. T2: also creates a new instance of MyObj and assign it to obj

您创建了两次您期望只创建一次的对象。 这不是最糟糕的场景。 您可以最终返回一个不再指定给您变量的对象 。

该代码不安全。 如果多线条执行函数, 则可以创建多例 MyObj 。 您需要在此同步 。

根本问题是,这块块代码:

if (obj == null) {
     obj = new MyObj();// costly initialisation
}

事实上,它远不是原子,它远不是原子。

另一种处理方式是重复检查(NOTE: 仅与爪哇 5 或较新的 Java 5 合作, 详情请见< a href="http://www.cs. umd.edu/~pugh/java/memoryModel/ DoubleCheckedLocking.html" rel=“ no follow” >这里 ):

public class DoubleCheckingSingletonExample
{
    private static final Object lockObj = new Object();

    private static volatile DoubleCheckingSingletonExample instance;

    private DoubleCheckingSingletonExample()
    {
        //Initialization
    }

    public static DoubleCheckingSingletonExample getInstance()
    {
        if(instance == null)
        {
            synchronized(lockObj)
            {
                if(instance == null)
                {
                    instance = new DoubleCheckingSingletonExample();
                }
            }
        }

        return instance;
    }
}

当同时从两条线索中调出“ 获取 Instance” 时, 双方将首先看到该实例为空, 另一则将进入同步区块, 并立即执行对象。 另一则将看到该实例不再为空, 并且将不再尝试进行即时处理。 进一步呼吁“ 获取Instance” 将看到该实例不是空的, 并且将不试图锁定它 。





相关问题
Spring Properties File

Hi have this j2ee web application developed using spring framework. I have a problem with rendering mnessages in nihongo characters from the properties file. I tried converting the file to ascii using ...

Logging a global ID in multiple components

I have a system which contains multiple applications connected together using JMS and Spring Integration. Messages get sent along a chain of applications. [App A] -> [App B] -> [App C] We set a ...

Java Library Size

If I m given two Java Libraries in Jar format, 1 having no bells and whistles, and the other having lots of them that will mostly go unused.... my question is: How will the larger, mostly unused ...

How to get the Array Class for a given Class in Java?

I have a Class variable that holds a certain type and I need to get a variable that holds the corresponding array class. The best I could come up with is this: Class arrayOfFooClass = java.lang....

SQLite , Derby vs file system

I m working on a Java desktop application that reads and writes from/to different files. I think a better solution would be to replace the file system by a SQLite database. How hard is it to migrate ...

热门标签