如何防止Singleton类方法在Java中是线程安全的?

时间:2011-02-14 11:45:46

标签: java multithreading thread-safety

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

我的问题是如何在不使用同步方法的情况下保护单例和池类中的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());
        }

    }


}

2 个答案:

答案 0 :(得分:2)

您可以使用线程安全的BlockingQueue。在尝试删除元素之前,您不需要检查集合是否为空,集合有一个方法来执行此操作。

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

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());
    }
}

答案 1 :(得分:0)

我认为你可以可能调用GetListObjectCount之类的方法而不使用synchronized的唯一方法是,如果列表本身是线程安全的并且行为合理在面对并发修改时调用此方法。

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

底线是“线程安全”不是一个简单的二元概念。你不能只说一个特定的类和/或方法是线程安全的;相反,它是关于你可以使用有用和正确的语义调用的方法组合。