Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/375.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 阻塞队列的线程安全';s drainTo()方法_Java_Thread Safety_Blockingqueue - Fatal编程技术网

Java 阻塞队列的线程安全';s drainTo()方法

Java 阻塞队列的线程安全';s drainTo()方法,java,thread-safety,blockingqueue,Java,Thread Safety,Blockingqueue,的文档说批量操作不是线程安全的,尽管它没有明确提到方法drainTo() BlockingQueue实现是 线程安全。所有排队方法 使用 内部锁或其他形式的锁 并发控制。然而,大部分 收集操作addAll, 包含所有、保留和移除所有 不一定要执行 除非另有规定,否则按原子顺序 在实现中。的确如此 可能,例如,对于addAll(c) 失败后失败(抛出异常) 只添加c中的一些元素 drainTo()方法的文档指定不能以线程安全的方式修改BlockingQueue元素将被导出到的集合。但是,它并没有提

的文档说批量操作不是线程安全的,尽管它没有明确提到方法drainTo()

BlockingQueue实现是 线程安全。所有排队方法 使用 内部锁或其他形式的锁 并发控制。然而,大部分 收集操作addAll, 包含所有、保留和移除所有 不一定要执行 除非另有规定,否则按原子顺序 在实现中。的确如此 可能,例如,对于addAll(c) 失败后失败(抛出异常) 只添加c中的一些元素

drainTo()方法的文档指定不能以线程安全的方式修改BlockingQueue元素将被导出到的集合。但是,它并没有提到drainTo()操作是线程安全的

从中删除所有可用元素 此队列并将它们添加到给定的 收集这个操作可能更复杂 这比重复轮询更有效 队列运行时遇到的故障 正在尝试将元素添加到 集合c可能会生成元素 两者都不在,要么都在,要么都在 关联时的集合 异常被抛出。抽干 队列本身导致 非法辩论例外。此外 此操作的行为是 如果指定的集合 在运行操作时修改 进步


那么,drainTo()方法是线程安全的吗?换句话说,如果一个线程在阻塞队列上调用了drainTo()方法,而另一个线程在同一队列上调用add()或put(),那么在两个操作结束时,队列的状态是否一致?

我认为您混淆了“线程安全”和“原子”这两个术语。它们的意思不一样。方法可以是线程安全的而不是原子的,也可以是原子的(对于单个线程)而不是线程安全的

线程安全是一个橡胶术语,如果不是圆形的话很难定义。Goetz认为,一个好的工作模型是,如果一个方法在多线程上下文中使用时与在单线程上下文中运行时一样“正确”,那么它就是线程安全的。弹性在于正确性是主观的,除非你有一个正式的规范来衡量

相比之下,原子很容易定义。它只是意味着操作要么完全发生,要么根本不发生

因此,您的问题的答案是
drainTo()
是线程安全的,但不是原子的。它不是原子的,因为它可以在中途抛出异常。但是,如果将其模化,则无论其他线程是否同时对队列执行操作,队列仍将处于一致状态


(上述讨论暗示,
BlockingQueue
接口的具体实现正确地实现了该接口。如果它没有正确实现,则所有赌注都被取消。)

drainTo()
是线程安全的,因为同时对队列执行的任何操作都不会更改结果,也不会损坏队列的状态。否则,该方法将毫无意义


如果目标集合(添加结果的集合)做了一些“聪明”的事情,您可能会遇到问题。但是,由于您通常会将队列耗尽到只有一个线程可以访问的集合中,因此这更像是一个理论问题。

偶然发现了这个问题,并想添加一个实现信息

从PriorityBlockingQueue的开始:

 /**
     * @throws UnsupportedOperationException {@inheritDoc}
     * @throws ClassCastException            {@inheritDoc}
     * @throws NullPointerException          {@inheritDoc}
     * @throws IllegalArgumentException      {@inheritDoc}
     */
    public int drainTo(Collection<? super E> c, int maxElements) {
        if (c == null)
            throw new NullPointerException();
        if (c == this)
            throw new IllegalArgumentException();
        if (maxElements <= 0)
            return 0;
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            int n = Math.min(size, maxElements);
            for (int i = 0; i < n; i++) {
                c.add((E) queue[0]); // In this order, in case add() throws.
                dequeue();
            }
            return n;
        } finally {
            lock.unlock();
        }
    }
/**
*@throws UnsupportedOperationException{@inheritardoc}
*@crows ClassCastException{@inheritDoc}
*@throws-NullPointerException{@inheritardoc}
*@inheritDoc}
*/

public int drainTo(CollectionThank。我不关心原子性。我关心线程安全。当drainTo()正在进行时,必须保留对该队列的任何新添加。仅此而已。该元素是否在正在进行的drainTo()中可用并不重要操作或在下一个操作中。@Shashikant-好吧,javadoc明确表示所有BlockingQueue API操作都是线程安全的。
drainTo
就是这样一个操作,因此它是线程安全的。您还需要知道什么?(提示:如果您不相信文档,可以查看源代码。)Stephan,文档还说批量操作不是线程安全的绝对是一个批量操作。@Stephen,drainTo指定如果impl.允许并发修改,行为将是未定义的。@bestsss它在哪里指定的?我在java 6、7或8 javadoc中没有看到关于
BlockingQueue
的这样的语句。我在页面上搜索了“defined”。它只提到如果集合被抽干到被修改了,但是与BlockingQueue接口本身的实现无关,它允许并发修改。这里有一个简单的答案:大多数(如果不是全部的话)impl.将阻止在Draino期间添加/删除/轮询等操作,即操作将被同步。以下是文档所述:此外,如果在操作进行过程中修改指定集合,则此操作的行为未定义。如果添加/删除/轮询/提供等与drainTo@bestsss“指定的集合”指的是队列将被排放到的集合。这是一个公平的点,但如果阻塞队列允许并发访问,则行为将同样未定义。@bestsss您认为这是为什么?文档明确声明了其他情况-阻塞队列实现是线程安全的。