代码之家  ›  专栏  ›  技术社区  ›  j2emanue

使用SynchronousQueue解决消费者-生产者并发问题。公平属性不起作用

  •  1
  • j2emanue  · 技术社区  · 9 年前

    我在调试SynchronousQueue时遇到问题。它在android工作室中,但它的java代码并不重要。我将true传递给SynchronousQueue的构造函数,因此它的“公平”意味着它是一个fifo队列。但它不遵守规则,它仍然让消费者先印刷,生产者后印刷。我的第二个问题是,我希望这些线程永远不会死,你认为我应该在生产者线程和消费者线程上使用while循环,让它们继续“生产和消费”彼此吗?

    这是我的简单代码:

       package com.example.android.floatingactionbuttonbasic;
    
    
    import java.util.concurrent.SynchronousQueue;
    
    import trikita.log.Log;
    
    
    public class SynchronousQueueDemo {
    
    
        public SynchronousQueueDemo() {
        }
    
    
        public void startDemo() {
            final SynchronousQueue<String> queue = new SynchronousQueue<String>(true);
    
            Thread producer = new Thread("PRODUCER") {
                public void run() {
                    String event = "FOUR";
                    try {
                        queue.put(event); // thread will block here
                       Log.v("myapp","published event:", Thread
                               .currentThread().getName(), event);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
    
                }
            };
    
            producer.start(); // starting publisher thread
    
            Thread consumer = new Thread("CONSUMER") {
                public void run() {
                    try {
                        String event = queue.take(); // thread will block here
                        Log.v("myapp","consumed event:", Thread
                                .currentThread().getName(), event);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
    
                }
            };
    
            consumer.start(); // starting consumer thread
    
        }
    
    }
    

    启动我简单调用的线程 new SynchronousQueueDemo().startDemo();

    无论我将什么传递给synchronousQueue构造函数,日志总是这样:

    /SynchronousQueueDemo$2$override(26747): myapp  consumed event: CONSUMER    FOUR
    V/SynchronousQueueDemo$1$override(26747): myapp published event:PRODUCER    FOUR
    

    检查 docs here ,上面写着:

    public SynchronousQueue(布尔公平) 使用指定的公平策略创建SynchronousQueue。 参数: fair-如果为true,则等待线程按FIFO顺序争用访问;否则未指定顺序。

    2 回复  |  直到 9 年前
        1
  •  1
  •   Ian Mc    9 年前
    1. 公平策略与队列的读取顺序有关。生产者/消费者的执行顺序是消费者接受(),释放生产者(在put()上被阻塞)。如果消费顺序很重要,则设置公平=真。

    2. 如果你想让线程保持活动状态,那么有一个循环条件,当被中断时表现良好(见下文)。可能你想放一根线。Producer中的sleep(),以限制生成事件的速率。

      public void run() {
          boolean interrupted = false;
          while (!interrupted) {
              try {
                   // or sleep, then queue.put(event)
                   queue.take(event); 
              } catch (InterruptedException e) {
                  interrupted = true;;
              }
          }
      }
      
        2
  •  1
  •   thedarkpassenger    9 年前

    SynchronousQueue使用一个简单的概念。只有有消费者才能生产。

    1) 现在如果你开始 queue.put() 没有任何 queue.take() ,线程将在那里阻塞。所以只要你有 queue.take() ,将取消阻止Producer线程。

    2) 同样,如果你开始 queue.take() 它会一直阻塞,直到有制作人。所以一旦你有了 queue.put() ,消费者线程将被阻止。

    所以只要 queue.take() 执行时,生产者和消费者线程都被解除阻塞。但您确实意识到生产者和消费者都在不同的线程中运行。因此,您在阻塞调用之后发出的任何消息都可以执行。在我的例子中,输出的顺序是这样的。制片人先被印刷了。

    V/SynchronousQueueDemo$1$override(26747):myapp发布的事件:PRODUCER FOUR /SynchronousQueueDemo$2$override(26747):myapp消费事件:CONSUMER FOUR