【问题标题】:Concurrency Issue with ConcurrentLinkedQueue with multiple threads writing and multiple threads reading. #Fast directory scanConcurrentLinkedQueue 的并发问题,多线程写入和多线程读取。 #快速目录扫描
【发布时间】:2017-01-29 04:51:44
【问题描述】:

我有多个线程从同一个队列写入和读取。我正在使用 ConcurrentLinkedQueue。任何线程都可以将元素添加到队列中,并且任何其他线程都可以轮询一个元素并对其进行处理。我的问题是,如果队列为空,我希望在队列上轮询的线程等到某个元素被其他线程添加到它,如果所有线程都在等待而没有线程正在写入,则整个进程应该退出。 我正在使用它来列出目录及其子目录中的所有文件#faster scan。

以下是代码sn-p 1:

{

私有队列 dList = new ConcurrentLinkedQueue();

/* 一些处理代码 */

public void Run
{
/* some processing code */
while(dName == null)
{
try{
synchronized(dList){
dList.wait();
}
} catch(InterruptedException e){}
dName = dList.poll();
}

/* some processing code */
{
dList.add(item);
synchronized(dList){
dList.notifyAll();
}
}
}

上面的代码对吗?它是否一直在做我想做的事。虽然程序运行良好,但我不明白线程是如何退出的,因为我没有提到任何退出条件。

在 ConcurrentLinkedQueue 上使用同步是否正确? 这也适用于巨大的目录吗? 编辑1: 使用 LinkedBlockingQueue,但是当所有线程都处于等待状态时如何退出,这意味着没有更多的目录可以扫描? 它是否可以使用一个静态变量,增加它并检查它是否等于线程数,然后退出。它有效还是有更好的解决方案?

编辑 2: 谢谢你们。 退出线程由 AtomicInteger 解决。如果所有线程都在队列中等待,则它们的 AtomicInteger 递增,如果 AtomicInteger 等于线程数则中断;

【问题讨论】:

    标签: java multithreading


    【解决方案1】:

    您所描述的是阻塞。您最好使用专门执行此操作的数据结构,例如ArrayBlockingQueue,而不是汇总您自己的数据结构。它具有并发性,但也有访问队列的阻塞方式,迫使正在运行的线程等待,直到有一个项目要获取。具有所有必需的锁定等。您还可以使用LinkedBlockingQueue 做无限的事情

    https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ArrayBlockingQueue.html https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/LinkedBlockingQueue.html

    这样您就可以拥有消费者线程和生产者线程,而您不必自己进行任何锁定或同步。您只需使用 take() 或执行 put(item) ,如果没有空间放置该项目或没有项目可取,线程将等待。它为您进行相关的锁定和解锁。并且仅在它无法真正获取该项目或将其放在那里时才等待。还有一些操作会超时等。

        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    if (Thread.currentThread().isInterrupted()) return;
                    try {
                        File file = blockingqueue.take();
                    } catch (InterruptedException ignored) {
                        return;
                    }
                    processFile(file);
                }
            }
        }).start();
    

    您实际上不必同步 ConcurrentLinkedQueue,它是线程安全的。你正在做的是实现阻塞。有很多事情可以解释如何做到这一点。无论您等待和通知什么对象(尽管必须是同一个对象),都适用相同的规则。

    • 你需要在一个线程中 wait() 并在另一个线程中 notify()(我不能 告诉你的代码是否是这种情况)。
    • 您需要在同一个对象上同步的同步块中执行此操作。 (正确)
    • 但是,您似乎没有实现任何其他要求。你需要在等待之前检查队列是否为空,每次都无缘无故等待是没有意义的。

    【讨论】:

    • 那么我必须在添加和轮询时同步它。我必须遍历巨大的目录,这不是昂贵的操作吗?
    • 通过阻塞操作 take 和 put() 他们将强制停止线程,直到有空间放置项目或项目。但是,所有的同步都是为你完成的。无需重建轮子。
    • 这是一个有界缓冲区,我不知道目录中有多少文件。
    • 然后使用数据结构的无限版本。所以 LinkedBlockingQueue
    • 所以你会设置一个线程来获取()文件并处理它,然后循环它。然后将适当处理馈入链接阻塞队列的任何内容。它不需要检查是否有文件要取,只需尝试 take() 它,它会等到有东西要取,然后正确抓取。对于任意数量的线程。
    猜你喜欢
    • 2011-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-02-01
    • 1970-01-01
    • 2017-09-13
    • 2011-03-07
    相关资源
    最近更新 更多