0

我已经通过一个单例类实现了一个异步线程,其中存在一个队列,我向其中添加了日志记录对象。但它在 java.util.linkedlist.remove 没有给出这样的元素异常

public class LogDaoSingleton extends Thread {

private static LogDaoSingleton logDaoSingleton = new LogDaoSingleton();

private static Queue<ScoreLoggingObject> queue = new LinkedList<ScoreLoggingObject>();

private static Boolean firstTime = true;


private LogDAO logDAO;
private SkipLogDaoImpl skipLogDAO;

Connection conNull = null;
Connection connection = null;

private int counter = 0;

Connection con = null;

Connection skipCon = null;

public static LogDaoSingleton getInstance() {
    return logDaoSingleton;
}

private static void createInstance() {
    logDaoSingleton = new LogDaoSingleton();
}

private LogDaoSingleton() {
    try {
        con = HMDBUtil.getNonTxNullProdConnection();
        conNull = HMDBUtil.getNonTxNullProdConnection();
        skipCon = HMDBUtil.getNonTxNullProdConnection();
        logDAO = new LogDAOImpl();
        skipLogDAO = new SkipLogDaoImpl();
        hmCandScoreLog = PropertyReader.getStringProperty(
                CacheConstants.CLUSTER_REPORT,
                CacheConstants.HM_CAND_SCORE_LOG);
        hmCandScoreLogNull = PropertyReader.getStringProperty(
                CacheConstants.CLUSTER_REPORT,
                CacheConstants.HM_CAND_SCORE_LOG_NULL);
    } catch (HMCISException e) {
        e.printStackTrace();
    }
}

public static void addtoQueue(ScoreLoggingObject scoringObject) {
    queue.add(scoringObject);
    if (firstTime) {
        synchronized (firstTime) {
            if (firstTime) {
                createInstance();
                logDaoSingleton.setDaemon(false);
                logDaoSingleton.start();
                firstTime = false;
            }
        }
    }
}

public void run() {
    try {
        while (true) {
            try {
                if (null != queue && queue.size() > 0) {
                    logData(queue.poll());
                } else {
                    try {
                        Thread.sleep(2 * 60 * 1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            } catch (Exception e) {
                // Do nothing.
            }
        }
    } catch (Throwable e) {
        firstTime = true;
    }
}

private void logData(ScoreLoggingObject scoreLoggingObject) {

    }
}

}

错误在logData(queue.poll());

4

1 回答 1

2

这种方法至少存在三个问题:

public static void addtoQueue(ScoreLoggingObject scoringObject) {
    queue.add(scoringObject);
    if (firstTime) {
        synchronized (firstTime) {
            if (firstTime) {
                createInstance();
                logDaoSingleton.setDaemon(false);
                logDaoSingleton.start();
                firstTime = false;
            }
        }
    }
}

  1. 你正在添加一个LinkedList没有锁的东西。LinkedList不是并发安全集合。尝试ConcurrentSkipLinkedList作为更好的收藏。

  2. 您正在阅读firstTime使用双重检查锁定...可能会产生您可能不相信的副作用...去看看“Java Concurrency in Practice”,特别是第 32 页上的 Yuck-face 列表。尝试预测什么该程序将在阅读本书之前输出。然后阅读说明。不幸的是,当我指出 JVM 有权在同步点之间重新排序操作时,我将不得不破坏该示例对您的影响。所以结果是您的同步块中的操作可以按任何顺序实现......例如它们可以按以下顺序发生(可能不是,但如果按此顺序执行,JVM 实现仍然有效)

        synchronized (firstTime) {
            if (firstTime) {
                firstTime = false;
                createInstance();
                logDaoSingleton.setDaemon(false);
                logDaoSingleton.start();
            }
        }
    

    如果您的 createInstance() 方法中抛出异常会发生什么?

    如果是我,我会通过强制 JVM 遵守顺序来解决这个问题firstTimevolatile尽管您仍然需要仔细检查!)

  3. firstTimeBoolean由自动装箱初始化的,对于布尔值使用池实例,所以你的双重检查锁实际上是synchronized (Boolean.TRUE)而不是synchronized (firstTime)。此外,在非最终字段上同步是一种不好的形式,因为它几乎从不做你想做的事情。您可能只想使addToQueue方法同步,直到您知道有问题为止。

TL; DR 您正试图通过锁定变得“聪明”……总是一个糟糕的计划……尤其是在您知道自己需要聪明之前。写出可能可行的最简单的东西,然后继续解决剩下的问题。然后看看性能问题在哪里......只有这样你才应该担心锁定这个类。

于 2012-11-26T09:23:40.937 回答