【问题标题】:Java multithreading issue - Consumer/Producer patternJava 多线程问题 - 消费者/生产者模式
【发布时间】:2013-07-19 09:32:39
【问题描述】:

已尝试解决此问题,但证明很困难。

我有两个线程,一个是生产者,另一个是消费者。都在不同的班级。两个线程独立运行。生产者正在汇集大约 8-12 个文件夹用于输入。然后它同时翻译所有文件,并将其放置在一个名为“readyToLoad”的共享文件夹中。 生产者线程完成后,消费者线程现在进入“readyToLoad”文件夹并开始处理翻译后的文档。

现在的问题是,当消费者处理翻译文件时,它不允许生产者将更多翻译文件放入“readyToLoad”文件夹。

我的问题是,如何防止消费者锁定“readyToLoad”文件夹?我该如何处理这种情况?

对于冗长的文字表示歉意,但我认为这将有助于了解我遇到问题的地方。感谢大家的帮助。

更新:添加了消费者代码(在加载过程中执行加载并锁定文件的代码)

public class LoadManager {
protected static final Logger logger = KCLogger.getLogger();
 ArrayList<Loader> threads = new ArrayList<Loader>();
 KCBLConfig config;
 private static final ExecutorService service = Executors.newFixedThreadPool(10);
 public LoadManager(KCBLConfig config) {
    this.config = config;
 }

public void start() throws Exception {
    logger.log(Level.INFO, "Starting loading threads.");
    try {
        TreeMap<String, ConnectionHandler> connectionHandlers = config.getConnectionHandlers();
        Iterator i = connectionHandlers.keySet().iterator();
        while (i.hasNext()) {

            ConnectionHandler connectionHandler = connectionHandlers.get((String) i.next());

            for (LoadFolder loadFolder : connectionHandler.getKcXMLFolders()) {
               Loader loader = new Loader(loadFolder.getId(), loadFolder, config.getConnectionHandlers());
               Thread loaderThread = new Thread(loader);
                loaderThread.start();   
               //service.submit(loader);
              // service.shutdown();
               //service.awaitTermination(1, TimeUnit.MILLISECONDS);
                threads.add(loader);
            }
        }
    } catch (Exception e) {
        logger.log(Level.SEVERE, "There was an error starting the loaders. Stopping all loader threads.", e);
        this.stop();
        throw e;
    }
    logger.log(Level.INFO, "All loader threads created. There are " + threads.size() + " loader threads");
}

【问题讨论】:

  • 如果我理解正确,消费者正在锁定文件夹,而您不希望这样。然后向我们展示消费者用来从该文件夹获取文件的代码。我看不出它如何在没有特定代码的情况下锁定文件夹。
  • 为什么不用可重入锁?
  • @JBNizet 刚刚在我的帖子中添加了一些代码
  • This 可能有用。

标签: java multithreading concurrency locking java.util.concurrent


【解决方案1】:

Java 生产者/消费者习惯用法现在通常使用BlockingDeque

我会为生产者和消费者设置单独的文件夹。为什么要承担这种复杂性?

【讨论】:

  • 你的意思是有一个单独的文件夹供生产者翻译成例如'translatedFolder'?和另一个文件夹“readyToUpload”文件夹供消费者处理翻译文件?还有另一个函数将每个翻译文件复制到“readyToUpload”目录中?只是想了解您所说的单独文件夹是什么意思..
  • 我有一个输入框和一个输出框。我不在乎你给他们起什么名字。
  • 是的,我确实有这两个文件夹。这正是他们的名字。
  • 每个线程应该只处理一个文件夹。听起来您希望两个线程访问同一个线程。我会找到一种完全隔离它们的方法。不然还有什么意义?
  • @duffymo:我不确定你的推理。消费者必须以某种方式获得生产者生产的东西。因此,如果生产者生产的是文件,那么消费者必须以某种方式读取它们。拥有两个单独的文件夹会有什么帮助?
【解决方案2】:

您可以在 Java 中使用 Monitor http://en.wikipedia.org/wiki/Monitor_(synchronization)synchronized 方法。

【讨论】:

    【解决方案3】:

    如果我理解正确,您在生产者和消费者之间没有任何通知机制。生产者将文件存储在一个文件夹中,消费者有一个无限循环,它会从该文件夹中读取所有文件并将它们移动到其他位置。

    这就是问题所在。这是我将如何解决它。

    生产者和消费者都应该共享一个 BlockingQueue 实例。每次生产者完成文件的生产(文件完全写入共享文件夹)时,它会将文件名添加到阻塞队列中。

    消费者从队列中获取文件名。这是一个阻塞操作,所以在文件名可用之前消费者会被阻塞。当消费者从队列中得到一个文件名时,它会读取这个文件(并且只读取这个文件),然后用它做任何他想做的事情。

    这有几个优点:

    • 生产者和消费者同时访问一个文件没有风险
    • 您可以拥有任意数量的生产者和消费者
    • 消费者不会无休止地扫描目录
    • 您可以设置队列的界限以避免产生过多的文件,并让消费者有机会跟上生产者的步伐。

    【讨论】:

    • 其实已经想到了BlockingQueue。我在进行测试时在代码中的某个地方实例化了它,可能是我没有正确实现它......我认为可能仍然存在问题,因为生产者也在循环中,不断汇集目录并提交给共享文件夹.. 块会让消费者立即停止生产者是否准备好将文件分块到 sharedDirectory 中?
    • 您能改写一下这个问题吗?我不明白。
    • 当然。我的问题是,当消费者执行操作时,生产者仍然能够写入 sharedFolder 吗?即生产者在上传翻译后的文件时同时翻译文件并将其放入 sharedFolder 中。..
    • 我看不出它为什么不能这样做的任何原因。我所知道的所有操作系统都支持在 sam 文件夹中并行读取一个文件并写入另一个文件。
    • 太棒了!还有一件事,你有任何 BlockingQueue 实现的例子吗?它不必定制我的要求,但如果是这样,那就太棒了:) 感谢您到目前为止的帮助
    猜你喜欢
    • 1970-01-01
    • 2013-04-12
    • 1970-01-01
    • 1970-01-01
    • 2016-01-22
    • 1970-01-01
    • 2014-10-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多