Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/iphone/38.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 我应该在什么时候通过LinkedBlockingQueue使用SynchronousQueue_Java_Concurrency_Blockingqueue - Fatal编程技术网

Java 我应该在什么时候通过LinkedBlockingQueue使用SynchronousQueue

Java 我应该在什么时候通过LinkedBlockingQueue使用SynchronousQueue,java,concurrency,blockingqueue,Java,Concurrency,Blockingqueue,有什么区别?什么时候我应该对容量为1的LinkedBlockingQueue使用SynchronousQueue SynchronousQueue更像是一个切换,而LinkedBlockingQueue只允许一个元素。不同之处在于,对SynchronousQueue的put()调用在出现相应的take()调用之前不会返回,但对于大小为1的LinkedBlockingQueue,put()调用(对空队列)将立即返回 我不能说我自己曾经直接使用过SynchronousQueue,但它是用于Execu

有什么区别?什么时候我应该对容量为1的
LinkedBlockingQueue
使用
SynchronousQueue

SynchronousQueue更像是一个切换,而LinkedBlockingQueue只允许一个元素。不同之处在于,对SynchronousQueue的put()调用在出现相应的take()调用之前不会返回,但对于大小为1的LinkedBlockingQueue,put()调用(对空队列)将立即返回

我不能说我自己曾经直接使用过SynchronousQueue,但它是用于
Executors.newCachedThreadPool()
方法的默认阻塞队列。它本质上是一个BlockingQueue实现,适用于您不需要队列(您不想维护任何挂起的数据)的情况

就我所知,上面的代码也做同样的事情

不,代码完全不同

同步。需要有服务员才能成功提供服务。LBQ将保留该商品,即使没有服务员,报价也将立即结束

SyncQ对于任务切换非常有用。假设您有一个带有挂起任务的列表和3个可用线程在队列中等待,尝试使用列表的1/4执行
offer()
,如果不接受,线程可以自己运行任务。[如果您想知道为什么是1/4而不是1/3,那么最后1/4应该由当前线程处理]

考虑尝试将任务交给工作人员,如果没有可用的任务,您可以选择自己执行任务(或引发异常)。相反,使用LBQ时,将任务留在队列中并不保证任何执行


注意:消费者和发布者的情况相同,即发布者可能会阻止并等待消费者,但在
提供
轮询
返回后,它会确保任务/元素得到处理。

使用SynchronousQueue的一个原因是为了提高应用程序性能。如果必须在线程之间进行切换,则需要一些同步对象。如果您能够满足使用它所需的条件,SynchronousQueue是我找到的最快的同步对象。其他人也同意。请参阅:

SynchronousQueue以类似的方式工作,主要区别如下: 1) SynchronousQueue的大小为0 2) 如果take()方法能够在同一时刻从队列中提取元素,则put()方法将仅插入元素,即,如果使用者take()调用将花费一些时间来使用某个元素,则无法插入该元素

SynchronousQueue-仅当有人在该时刻收到它时才插入。

[只是尝试用(可能)更清晰的词来表达它。]

我非常清楚地相信这些国家的情况:

  • 一种阻塞队列,其中每个插入操作必须等待另一个线程执行相应的删除操作,反之亦然
  • 同步队列没有任何内部容量,甚至没有1的容量。您无法窥视同步队列,因为只有在您尝试删除某个元素时,该元素才存在;除非另一个线程试图删除某个元素,否则不能插入该元素(使用任何方法);您不能迭代,因为没有可迭代的内容
  • 队列头是第一个排队插入线程试图添加到队列中的元素;如果没有此类排队线程,则没有可用于删除的元素,
    poll()
    将返回
    null
  • 以及:

  • 一种队列,它还支持在检索元素时等待队列变为非空,在存储元素时等待队列中的空间变为可用的操作
  • 因此,差异是明显的,而且有点微妙,特别是下面的第三点:

  • 如果从
    BlockingQueue
    检索时队列为空,则操作将一直阻塞,直到插入新元素为止。此外,如果在插入
    阻塞队列时队列已满,则操作将阻塞,直到从队列中删除元素并为新队列留出空间为止。但是请注意,在
    SynchronousQueue
    中,由于在另一个线程上发生相反的操作(插入和删除操作彼此相反),操作被阻止因此,与
    阻塞队列
    不同,阻塞取决于操作的存在,而不是元素的存在或不存在
  • 由于阻塞依赖于相反操作的存在,因此元素永远不会真正插入队列中。这就是为什么第二点:“同步队列没有任何内部容量,甚至没有1的容量。”
  • 因此,
    peek()
    始终返回
    null
    (再次检查),并且
    迭代器()
    返回一个空迭代器,其中
    hasNext()
    始终返回
    false
    。(). 但是,请注意,
    poll()
    方法整洁地检索并删除此队列的头,如果另一个线程当前正在使元素可用,并且如果不存在这样的线程,则返回
    null
    。()

  • 最后,请注意,
    SynchronousQueue
    LinkedBlockingQueue
    类都实现了
    BlockingQueue
    接口。

    同步队列基本上用于切换目的。它们没有任何线程,put操作被阻塞,直到其他线程执行get操作

    如果我们想在两个线程之间安全地共享一个变量,我们可以将该变量放入同步队列中,让另一个线程从队列中获取它

    源代码示例

    ExecutorService executor=Executors.newFixedThreadPool(2);
    SynchronousQueue=新的SynchronousQueue();
    可运行生产者=()->{
    整数producedElement=ThreadLocalRandom
    .current()
    .nextInt();
    试一试{
    队列。put(生产删除);
    }捕获(Int)
    
    new SynchronousQueue()
    new LinkedBlockingQueue(1)
    
        ExecutorService executor = Executors.newFixedThreadPool(2);
        SynchronousQueue<Integer> queue = new SynchronousQueue<>();
    Runnable producer = () -> {
        Integer producedElement = ThreadLocalRandom
          .current()
          .nextInt();
        try {
            queue.put(producedElement);
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }
    };
    
    Runnable consumer = () -> {
        try {
            Integer consumedElement = queue.take();
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }
    };
    
    executor.execute(producer);
    executor.execute(consumer);
    
    executor.awaitTermination(500, TimeUnit.MILLISECONDS);
    executor.shutdown();
    assertEquals(queue.size(), 0);