admin管理员组

文章数量:1300024

Unexpected behavior with 2 enqueuer threads when using built-in java ArrayBlockingQueue and custom implementation

The behavior is that I expected is that each threads enqueues and deques in the sequential order that the threads used in enqueue the values, but this is not the case.

This is the code:

public class MultiThreadTests {
  private static final int QUEUE_LENGTH = 100_000;

  public static void main(String[] args) throws InterruptedException {
    usingTwoThreadsAndArrayBlockingQueue();

  }

  private static void usingTwoThreadsAndArrayBlockingQueue() throws InterruptedException {
    ArrayBlockingQueue<Integer> q = new ArrayBlockingQueue<Integer>(QUEUE_LENGTH);

    ArrayBlockingQueueClientThread t1 = new ArrayBlockingQueueClientThread(q, 1);
    ArrayBlockingQueueClientThread t2 = new ArrayBlockingQueueClientThread(q, 2000);

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

  }

  static class ArrayBlockingQueueClientThread extends Thread {
    ArrayBlockingQueue q;
    int m;

    ArrayBlockingQueueClientThread(ArrayBlockingQueue ephemeralQueue, int m) {
      this.q = ephemeralQueue;
      this.m = m;
    }

    public void run() {
      for (int i = 0; i < 20 ; i++) {
          q.add(i * m);
      }

      // I should still see the correct order when I dequeue concurrently, but I do not.
      int k = 0;
      while(k<20)
      {
        k++;
        try {
          System.out.println(q.poll(500, TimeUnit.MILLISECONDS));
        } catch (InterruptedException e) {
          throw new RuntimeException(e);
        }
      }
    }
  }
}

This is the output (it is not consistent however): | | | ----- | | 1 | | 2 | | 3 | | 4 | | 5 | | 6 | | 7 | | 8 | | 9 | | 0 | | 11 | | 12 | | 13 | | 10 | | 14 | | 16 | | 17 | | 18 | | 19 | | 0 | | 2000 | | 4000 | | 15 | | 8000 | | 10000 | | 12000 | | 14000 | | 16000 | | 18000 | | 6000 | | 22000 | | 24000 | | 26000 | | 28000 | | 30000 | | 20000 | | 34000 | | 36000 | | 32000 | | 38000 |

Some values are out of order at the thread level, such as value 15 and the value 6000. and I do not understand why this is the case. Any help is greatly appreciated.

Unexpected behavior with 2 enqueuer threads when using built-in java ArrayBlockingQueue and custom implementation

The behavior is that I expected is that each threads enqueues and deques in the sequential order that the threads used in enqueue the values, but this is not the case.

This is the code:

public class MultiThreadTests {
  private static final int QUEUE_LENGTH = 100_000;

  public static void main(String[] args) throws InterruptedException {
    usingTwoThreadsAndArrayBlockingQueue();

  }

  private static void usingTwoThreadsAndArrayBlockingQueue() throws InterruptedException {
    ArrayBlockingQueue<Integer> q = new ArrayBlockingQueue<Integer>(QUEUE_LENGTH);

    ArrayBlockingQueueClientThread t1 = new ArrayBlockingQueueClientThread(q, 1);
    ArrayBlockingQueueClientThread t2 = new ArrayBlockingQueueClientThread(q, 2000);

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

  }

  static class ArrayBlockingQueueClientThread extends Thread {
    ArrayBlockingQueue q;
    int m;

    ArrayBlockingQueueClientThread(ArrayBlockingQueue ephemeralQueue, int m) {
      this.q = ephemeralQueue;
      this.m = m;
    }

    public void run() {
      for (int i = 0; i < 20 ; i++) {
          q.add(i * m);
      }

      // I should still see the correct order when I dequeue concurrently, but I do not.
      int k = 0;
      while(k<20)
      {
        k++;
        try {
          System.out.println(q.poll(500, TimeUnit.MILLISECONDS));
        } catch (InterruptedException e) {
          throw new RuntimeException(e);
        }
      }
    }
  }
}

This is the output (it is not consistent however): | | | ----- | | 1 | | 2 | | 3 | | 4 | | 5 | | 6 | | 7 | | 8 | | 9 | | 0 | | 11 | | 12 | | 13 | | 10 | | 14 | | 16 | | 17 | | 18 | | 19 | | 0 | | 2000 | | 4000 | | 15 | | 8000 | | 10000 | | 12000 | | 14000 | | 16000 | | 18000 | | 6000 | | 22000 | | 24000 | | 26000 | | 28000 | | 30000 | | 20000 | | 34000 | | 36000 | | 32000 | | 38000 |

Some values are out of order at the thread level, such as value 15 and the value 6000. and I do not understand why this is the case. Any help is greatly appreciated.

Share Improve this question edited Feb 12 at 16:30 Gyul 6742 silver badges15 bronze badges asked Feb 11 at 15:05 AdrianAdrian 579 bronze badges
Add a comment  | 

2 Answers 2

Reset to default 4

Why do you expect sequential order?

The execution could be:

  • the first thread reads "0" from the queue
  • the second thread reads "1" and prints it, reads "2" and prints it, ..., reads "9" and prints it, reads "10"
  • the first thread manages to print out the "0" it fetched long ago, then reads "11" and prints it, reads "12" and prints it, reads "13" and prints it
  • the second thread prints out the "10", reads "14" and prints it
  • the first thread reads "15"

In your given code, q.add(...) and q.poll() may alternate.

t1 may have add(0), but t2 may have poll() the 0, causing t1 to poll() again, possibly taking the number that t2 inserted.

Because the poll() operation is competitive, there is no control over who poll() first to take out the head of the queue.

For Example:

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
0
1
2
3
[3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 0, 2000, 4000, 6000, 8000, 10000, 12000, 14000, 16000, 18000, 20000, 22000, 24000, 26000, 28000, 30000, 32000, 34000, 36000, 38000]
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
0
2000
4000
6000
8000
4
10000
12000
14000
16000
18000
20000
22000
24000
26000
28000
30000
32000
34000
36000
38000

本文标签: