# 目前队列存在的问题
- 很多场景要求分离生产者,消费者两个角色,它们得由不同的线程来担当,而之前的实现根本没有考虑线程安全问题
- 队列为空,那么在之前的实现里会返回 null,如果就是硬要拿到一个元素呢?只能不断循环尝试
- 队列为满,那么再之前的实现里会返回 false,如果就是硬要塞入一个元素呢?只能不断循环尝试
所谓的生产者就是一段代码它主要调用的是 offer 方法,为队列提供元素的这个称之为 生产者
所谓的消费者就是另一段代码它主要调用的是 poll 方法,从队列中获取元素的这个称之为 消费者
# 案例代码:
public class TestThreadUnsafe | |
{ | |
private final String[] array = new String[10]; | |
private int tail = 0; | |
public void offer(String e) | |
{ | |
array[tail] = e; | |
tail++; | |
} | |
@Override | |
public String toString() | |
{ | |
return Arrays.toString(array); | |
} | |
public static void main(String[] args) | |
{ | |
TestThreadUnsafe queue = new TestThreadUnsafe(); | |
// 如果将 两个添加 代码 换成 在 两个线程中去执行看看会有什么问题 | |
new Thread(() -> queue.offer("e1"), "t1").start(); | |
new Thread(() -> queue.offer("e2"), "t2").start(); | |
} | |
} |
# 分析代码:
t1 和 t2 都是要执行如下代码,但是 它们在执行时代码次序 可能会发生 交错的情况
tail
[null null null null null null null null null null]
0 1 2 3 4 5 6 7 8 9
============t1 和 t2两个线程的执行次序=============
t1 t2
array[tail] = e1;
tail++;
array[tail] = e2;
tail++;
上面的话什么意思呢?就是说 当 CPU 刚开始 指向 t1 的时候它先 指向了 赋值语句 array [tail] = e; 但是它还没来得及执行后面的自增操作:tail++; CPU 的执行权就会切换到 t2 切换到 t2 它可能会把 t2 这两行代码执行完了 它再切换回 t1 执行 自增操作 tail++;
这就是两个线程代码产生 交错的 情况
tail
[null null null null null null null null null null]
0 1 2 3 4 5 6 7 8 9
============t1 和 t2两个线程的执行次序=============
t1 t2
array[tail] = e1;
array[tail] = e2;
tail++;
tail++;
交错 就会导致我们的结果 出乎意料,导致一个不正确的结果
# 分析交错代码执行流程:
t1 执行中…
tail
[null null null null null null null null null null]
0 1 2 3 4 5 6 7 8 9
============t1 和 t2两个线程的执行次序=============
当 t1 将索引0的位置赋值为 e1 的时候 还没来得及执行 tail++ CPU就切换到了 t2
t1 t2
array[0] = e1;
array[tail] = e2;
tail++;
tail++;
t2 执行中…
此时由于上面t1执行的时候将 索引0位置赋值为 了e1
tail
[e1 null null null null null null null null null]
0 1 2 3 4 5 6 7 8 9
============t1 和 t2两个线程的执行次序=============
t1 t2
array[0] = e1;
执行t2到赋值语句此时 tail还处于索引0的位置,赋值后 并进行 tail++;
array[tail] = e2;
tail++;
tail++;
t1 执行中…
由于t1执行了赋值语句为e1时 还没有 tail++ CPU就切换到了t2 而t2赋值为了 e2 并将tail++了
tail
[e2 null null null null null null null null null]
0 1 2 3 4 5 6 7 8 9
============t1 和 t2两个线程的执行次序=============
t1 t2
array[0] = e1;
CPU切换到t1 将剩余代码执行完毕 tail++
array[tail] = e2;
tail++;
tail++;
t2 执行中…
CPU切换到t1 继续执行下面代码tail++
tail
[e2 null null null null null null null null null]
0 1 2 3 4 5 6 7 8 9
============t1 和 t2两个线程的执行次序=============
t1 t2
array[0] = e1;
CPU 切换到t2 执行赋值代码 并 tail++
array[tail] = e2;
tail++;
tail++;
当现在其实也不必在深究下去了,因为已经可以看出 出错了
当然这种 交错的情况 也只是 有可能而已 ,它也有可能是正常的 比如执行完了 t1 在 执行 t2 但是也有可能 t2 只执行了赋值语句没来得及执行 tail++CPU 就切换到了 t1 了