带有BlockingQueue的Java线程竞争条件

时间:2014-10-20 13:29:23

标签: java multithreading thread-safety race-condition blockingqueue

我的Java代码中存在使用BlockingQueue的潜在竞争条件,我想知道如何修改代码以避免它:

private static BlockingQueue<FileToFTP> ftpQueue = new LinkedBlockingQueue<FileToFTP>();

private static boolean shuttingDown = false;

private static FileToFTP pendingFile = null;
private static int uploadsPending = 0;

private static Thread ftpThread = new Thread(new Runnable() { 
            public void run() {
                try {
                    for(;;) {
                        FileToFTP f2f = ftpQueue.take();    // this blocks until there is something to take
                        // FIXME: If the main thread takes over right 
                        // at this instant, then uploadsRemaining() 
                        // is not correct!!
                        uploadsPending = 1;
                        int qs = ftpQueue.size();
                        logIt(qs, f2f);
                        pendingFile = f2f;
                        if(!doUploadFile(f2f.getPath(), f2f.getFilename(), f2f.getRenameTo(), f2f.isBinary())) {
                            if(shuttingDown) {
                                log.info("Upload " + f2f + " failed!");
                            } else {
                                ftpQueue.offer(f2f);    // put it back on to retry later
                            }
                            uploadsPending = 0;
                        } else {
                            pendingFile = null;
                            uploadsPending = 0;
                        }
                        if(qs == 0) logIt("");
                    }
                } catch (InterruptedException consumed) {
                    // Allow thread to exit
                }
            }
        });

public static int uploadsRemaining() {
    return ftpQueue.size() + uploadsPending;
}

请参阅代码中的“FIXME”评论。谢谢!

1 个答案:

答案 0 :(得分:1)

也许我误解了你想要的东西,但听起来你可能最好用ExecutorService来实际运行。您可以使用Exectors.newSingleThreadExecutor()Executors.newFixedThreadPool(2)创建它们(2是要使用的线程数的示例)。

然后Runnable上可以.execute.submit ExecutorServicesubmit将返回Future<T>对象,该对象可用于跟踪提交给ExecutorService的特定作业的状态。

话虽如此,您可能需要创建一个新类来执行此操作,因为Runnable / Callable类需要在其中包含FileToFTP变量。 (旁注:我试图避免内部课程,所以如果你想知道为什么我没有建议这样做......)

然后问题变成&#34;如何判断有多少文件待处理?&#34;不幸的是,唯一简单的方法是使它成为另一个类的静态属性...使用静态get / set方法或作为public / protected属性。 AtomicInteger是理想的选择,因此您可能需要考虑在调用类中使用一个作为受保护的静态实例。它有专用的递增/递减命令以及调整值并返回它的命令。