java - 2 个线程修改共享 BlockingQueue 的意外输出

标签 java multithreading

我有以下内容:

public class ProducerConsumer {

  private BlockingQueue<Integer> q;
  private Random rnd;
  private boolean run;

  public ProducerConsumer(){
    rnd = new Random();
    q = new ArrayBlockingQueue<>(10);
    run = true;
  }

  // high leve - with ArrayBlockingQueue

  public void QProducer() throws InterruptedException{       
    int i;
    while(run){
        i  = rnd.nextInt(100);

        q.put(i);
        System.out.println(i +" Added. Size is: "+ q.size());
    }
  } 

  public void  QConsumer() throws InterruptedException{
    int i;
    while(run){
      Thread.sleep(100);
      if (rnd.nextInt(10) == 0) {

          i = q.take();
          System.out.println(i + " Taken. Size is: "+ q.size());
      }
    }
  }

public void changeRun(){
    run = false;
 }    
}
<小时/>
 public static void main(String[] args) throws InterruptedException {

    // Producer Consumer

    final ProducerConsumer pc = new ProducerConsumer();

    Thread t1 = new Thread(new Runnable() {

        @Override
        public void run() {
            try {
                pc.QProducer();
            } catch (InterruptedException ex) {
                Logger.getLogger(Threading.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    });

    Thread t2 = new Thread(new Runnable() {

        @Override
        public void run() {
            try {
                pc.QConsumer();
            } catch (InterruptedException ex) {
                Logger.getLogger(Threading.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    });

    t1.start();
    t2.start();

    Scanner scn = new Scanner(System.in);

    scn.nextLine();
    pc.changeRun();

    t1.join();
    t2.join();

}

输出:

20 Added. Size is: 1
8 Added. Size is: 2
71 Added. Size is: 3
72 Added. Size is: 4
61 Added. Size is: 5
97 Added. Size is: 6
6 Added. Size is: 7
64 Added. Size is: 8
58 Added. Size is: 9
27 Added. Size is: 10
20 Taken. Size is: 10 *
93 Added. Size is: 10
8 Taken. Size is: 9
95 Added. Size is: 10
71 Taken. Size is: 10 *
70 Added. Size is: 10
72 Taken. Size is: 10 *
85 Added. Size is: 10
61 Taken. Size is: 9
43 Added. Size is: 10
64 Added. Size is: 10 **
... 

我想知道怎么会有数字被取走,但大小却保持不变(*), 以及如何在队列满后添加值( ** )。 AFAIU,BlockingQueue 是同步的,如果队列为空,则等待添加值,如果已满,则等待删除。 预先感谢您。

最佳答案

由于多线程,put() 和它后面的 println/size() 以及 take() 和它后面的 println/size() 可以交错。因此,size() 返回的值在打印时可能已经过时。例如

1a. Add (size = 10)
  1b. Print size 10
2a. Take (size = 9)
3a. Add (size = 10)
  2b. Print size 10
  3b. Print size 10

关于java - 2 个线程修改共享 BlockingQueue 的意外输出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13113460/

相关文章:

java - JAVA中使用信号量控制线程访问

java - 使用 Apache Jena ExtendedIterator 在具有大量三元组的图上进行迭代

java - org.apache.catalina.LifecycleException : Failed to start component [StandardEngine[Catalina]. StandardHost[本地主机].StandardContext[/mmasgis]]

java - 使用Thread.currentThread()。isInterrupted()与Thread.sleep()

c# - 如何在Windows Service中实现互斥

multithreading - Android ProgressBar 停止更新

Java 加法与预增量根据括号的使用给出不同的结果

java - 选择了 Android ListView 数组适配器

java - 无法找到或加载主类 Java 错误 Notepad++

c++ - 线程安全 : Multiple threads reading from a single const source