类的getter/setter方法和单例模式中的Java细粒度同步

类的getter/setter方法和单例模式中的Java细粒度同步,java,synchronization,locking,singleton,Java,Synchronization,Locking,Singleton,我试图使用synchronizationjava指令在类中实现细粒度同步,即尽可能少地同步代码。。我将对代码进行内联注释,以解释我所做的工作,在代码之后,我将询问您如何改进代码: 公共类MyClass{ 私有静态volatile MyClass singletonistance=null; 私有HashMap mHashMap=null; 私有字符串mStringA=null; 私有字符串mStringB=null; //使用双重检查技术仅使用同步 //在第一次调用getInstance()时

我试图使用
synchronization
java指令在类中实现细粒度同步,即尽可能少地同步代码。。我将对代码进行内联注释,以解释我所做的工作,在代码之后,我将询问您如何改进代码:

公共类MyClass{
私有静态volatile MyClass singletonistance=null;
私有HashMap mHashMap=null;
私有字符串mStringA=null;
私有字符串mStringB=null;
//使用双重检查技术仅使用同步
//在第一次调用getInstance()时
公共静态MyClass getInstance(){
if(singletonistance==null){
已同步(MyClass.class){
if(singletonistance==null)
singletonistance=newmyclass();
//初始化类成员变量
singletonistance.mHashMap=新HashMap();
singletonistance.mStringA=新字符串();
singletonistance.mStringB=新字符串();
}
}
回归单一立场;
}
//以下两种方法操作HashMap mHashMap
//以安全的方式,因为它们锁定了mHashMap实例
//都是一样的,都是独一无二的
公共整数getIntegerFromHashmap(字符串键){
已同步(mHashMap){
返回mHashMap.get(键);
}
}
public void setIntegerIntoHashmap(字符串键,整数值){
已同步(mHashMap){
mHashMap.put(键、值);
}
}
//对于两个字符串成员mStringA和mStringB,问题是
//成员所指向的字符串实例因
//setter方法,因此我们不能以细粒度的方式锁定
//必须锁定单站姿。
公共字符串getStringA(){
同步(单站姿){
返回mStringA;
}
}
公共字符串getStringB(){
同步(单站姿){
返回mStringB;
}
}
public void setStringA(字符串newString){
同步(单站姿){
mStringA=新闻字符串;
}
}
public void setString(字符串newString){
同步(单站姿){
mStringB=新闻字符串;
}
}
}
我不喜欢两个
String
成员变量的getter和setter方法,因为锁定
singletonistance
会使试图访问
mStringB
的线程等待操作
mStringA
的线程释放其锁。在这种情况下你会怎么做?您会在
MyClass
中创建两个成员变量,如
private final Integer mstringlock=new Integer(0)
private final Integer mStringBLock=new Integer(0)
,并分别在
mStringA
mStringB
的getter和setter方法的同步块中使用它们吗


如果您对如何改进上述代码和建议的
字符串
成员变量细粒度同步变体有一些想法,欢迎您:)

是的,如果希望线程能够同时调用这两个方法,您需要两个单独的锁。我想说这方面没有什么可以改进的

但是,我注意到您的
getInstance()
方法试图最小化要同步的块的大小,但实际上您没有做到这一点,即检查同步块内的
singletonInstance==null
。因此,我认为最好使用
synchronized
来限定整个方法


它缩短了该方法的代码,并且使其更自然。

是的,如果希望线程能够同时调用这两个方法,则需要两个单独的锁。我想说这方面没有什么可以改进的

但是,我注意到您的
getInstance()
方法试图最小化要同步的块的大小,但实际上您没有做到这一点,即检查同步块内的
singletonInstance==null
。因此,我认为最好使用
synchronized
来限定整个方法

它缩短了该方法的代码,也使其更加自然。

从何处开始

好的,双重检查锁定:它坏了(仍然),不要使用它。如果您觉得必须使用单例(实际上,通常使用依赖项注入是个坏主意),那么同步getter方法,并快速返回。在这种情况下,有争议的同步的可能性非常低,除非您拥有大量的内核(如,数千个),并且不断调用getter方法

HashMap
替换为
ConcurrentHashMap
。Doug Lea比你我都更擅长并发编码

将字符串变量标记为volatile,不要同步它们。

从何处开始

好的,双重检查锁定:它坏了(仍然),不要使用它。如果您觉得必须使用单例(实际上,通常使用依赖项注入是个坏主意),那么同步getter方法,并快速返回。在这种情况下,有争议的同步的可能性非常低,除非您拥有大量的内核(如,数千个),并且不断调用getter方法

HashMap
替换为
ConcurrentHashMap
。Doug Lea比你我都更擅长并发编码


将字符串变量标记为volatile,不要同步它们。

通常更简单的解决方案更容易实现。我还将使用并发库添加
public enum MyClass {
    INSTANCE;

    private final Map<String, Integer> mHashMap = new ConcurrentHashMap<String, Integer>();
    private volatile String mStringA = null;
    private volatile String mStringB = null;


    // The following two methods manipulate the HashMap mHashMap
    // in a secure way
    public Integer getIntegerFromHashmap(String key) {
        return mHashMap.get(key);
    }

    public void setIntegerIntoHashmap(String key, Integer value) {
        mHashMap.put(key, value);
    }

    public String getStringA() {
        return mStringA;
    }

    public String getStringB() {
        return mStringB;
    }

    public void setStringA(String newString) {
        mStringA = newString;
    }

    public void setStringB(String newString) {
        mStringB = newString;
    }
}