如何在Java中保护单例类方法是线程安全的?

如何在Java中保护单例类方法是线程安全的?,java,multithreading,thread-safety,Java,Multithreading,Thread Safety,我有一个线程安全的双重检查Singleton类,它在Singleton类中持有一个带有get/set/size方法的LinkedList。然后我有一个简单的pool类,它使用这个单例类来管理对象池 我的问题是,在不使用sync方法的情况下,如何在singleton和pool类中保护get/set方法。这是我的密码 public class SingletonDoubleCheckedLockingPattern { private static SingletonDoubleCheck

我有一个线程安全的双重检查Singleton类,它在Singleton类中持有一个带有get/set/size方法的LinkedList。然后我有一个简单的pool类,它使用这个单例类来管理对象池

我的问题是,在不使用sync方法的情况下,如何在singleton和pool类中保护get/set方法。这是我的密码

public class SingletonDoubleCheckedLockingPattern {

    private static SingletonDoubleCheckedLockingPattern s = new SingletonDoubleCheckedLockingPattern();

    private LinkedList<Object> linkedList;

    public int GetListObjectCount() {
        return linkedList.size();
    }

    public Object GetObjectFromList() {
        return linkedList.poll();
    }

    public void SetObjectFromList(Object ee) {
        linkedList.add(ee);
    }

    private SingletonDoubleCheckedLockingPattern() {

        linkedList = new LinkedList<Object>();

    }

    /**
     * SingletonHolder is loaded on the first execution of
     * Singleton.getInstance() or the first access to SingletonHolder.INSTANCE,
     * not before.
     */
    private static class SingletonHolder {
        public static final SingletonDoubleCheckedLockingPattern INSTANCE = new SingletonDoubleCheckedLockingPattern();
    }

    public static SingletonDoubleCheckedLockingPattern getInstance() {
        return SingletonHolder.INSTANCE;
    }

    // avoid cloning
    public final Object clone() throws CloneNotSupportedException {
        throw new CloneNotSupportedException();
    }

}

public class SingletonObjectPool  {

    private int maxlistValue = 10;


    public Object GetObject() 
    {
        int listCount = SingletonDoubleCheckedLockingPattern.getInstance().GetListObjectCount();
        if(listCount > 0)
        {
            return SingletonDoubleCheckedLockingPattern.getInstance().GetObjectFromList();
        }
        return null;
    }


    public void SetObject() 
    {
        int listCount = SingletonDoubleCheckedLockingPattern.getInstance().GetListObjectCount();
        if(listCount < maxlistValue)
        {
            SingletonDoubleCheckedLockingPattern.getInstance().SetObjectFromList(new Object());
        }

    }


}
公共类SingletonDoubleCheckedLockingPattern{
私有静态SingletonDoubleCheckedLockingPattern s=新的SingletonDoubleCheckedLockingPattern();
私有链接列表链接列表;
public int GetListObjectCount(){
返回linkedList.size();
}
公共对象GetObjectFromList(){
返回linkedList.poll();
}
public void SetObjectFromList(对象ee){
linkedList.add(ee);
}
私有单音双校验锁定模式(){
linkedList=新建linkedList();
}
/**
*SingletonHolder在第一次执行时加载
*Singleton.getInstance()或对SingletonHolder.INSTANCE的第一次访问,
*以前没有。
*/
私有静态类单音持有人{
公共静态最终SingletonDoubleCheckedLockingPattern实例=新的SingletonDoubleCheckedLockingPattern();
}
公共静态SingletonDoubleCheckedLockingPattern getInstance()的{
返回SingletonHolder.INSTANCE;
}
//避免克隆
公共最终对象克隆()引发CloneNotSupportedException{
抛出新的CloneNotSupportedException();
}
}
公共类SingletonObjectPool{
私有int maxlistValue=10;
公共对象GetObject()
{
int listCount=SingletonDoubleCheckedLockingPattern.getInstance().GetListObjectCount();
如果(列表计数>0)
{
返回SingletonDoubleCheckedLockingPattern.getInstance().GetObjectFromList();
}
返回null;
}
public void SetObject()
{
int listCount=SingletonDoubleCheckedLockingPattern.getInstance().GetListObjectCount();
如果(listCount
您可以使用线程安全的
阻塞队列。在尝试删除元素之前,不需要检查集合是否为空,集合有一个方法来执行此操作

为了简化代码并使其线程安全,您可以这样做

public class SingletonObjectPool  {
    private static final int maxlistValue = 10;
    private static final BlockingQueue queue 
        = new ArrayBlockingQueue(maxListValue);

    public static Object getObject() {
        return queue.poll();
    }


    public static void addObjectAsRequired() {
        queue.offer(new Object());
    }
}

我认为,您可以在不使用
synchronized
的情况下调用方法(如
GetListObjectCount
)的唯一方法是,如果列表本身是线程安全的,并且在面对并发修改时调用此方法时,它的行为是明智的

在这种情况下,不会有任何其他问题,因为对列表本身的引用永远不会更改。您可能希望将其声明为
final
,以使其非常清楚,并让编译器警告任何试图重新分配列表的人。(如果这是一项要求,那么引用至少需要是
volatile
,但它会在类的多个操作的正确性方面引发许多其他问题)


底线是“线程安全”不是一个简单的二进制概念。你不能只说一个特定的类和/或方法是线程安全的;更确切地说,这是关于您可以使用有用且正确的语义调用哪些方法组合。

为了便于搜索,我将您的引用从“single tone”更新为“singleton”,因为后者是正确的拼写。您没有使用双重检查锁定模式,这本身并不是问题。您还创建了两个实例,一个在类中,一个在holder中……您还需要调用单个方法,如
poll()
,而不是检查
size()
并执行
remove()
,因为这些操作之间可能存在竞争条件,注意:使其更安全也简化了代码。;)