自己用 Java 写一个阻塞队列
Java 内置了很多数据结构,阻塞队列也有。最近在看 Java 中的并发包:Lock
&Condition
。然后看到了有人说可以用他们实现阻塞队列,然后我想着,那我是不是也可以写一个阻塞队列?
阻塞队列的特点
想着就想着先写一个,阻塞队列的特点:
- 一个有限的存数据的队列;
- 入队的时候要判断队列是否已满;已满的时候,入队的线程要阻塞等待,直到队列有空位,被唤醒继续入队;
- 出队的时候要判断队列是否为空;为空的时候,获取队列数据的线程阻塞等待,直到队列有新数据的时候被唤醒继续执行;
也就是说我们在对队列操作的时候有两个操作,一个入队,一个出队:
入队线程:enq thread
; 出队线程 deq thread
。两者在进行入队和出队的时候都会要先获取全局 lock。默认我们使用的是 size 来存储 list 的容量,入队的时候:size+1;出队的时候 size-1;然后我们用了两个 condition
来告诉当前入队线程和出队线程当前是应该等待,还是可以继续执行。当队列容量不够的时候,入队线程进入 await
,否则就入队,并且唤醒出队的线程。出队的线程进入之后先判断队列是否为空,为空的时候就await
,然后等地啊被唤醒。大致流程就是这样:
然后就写了下面的比较初级的代码。
v1 版本:
1 |
|
然后写了个main
测试方法:
1 |
|
然后就会发现一个报错:
1 | Exception in thread "consumer-4" java.lang.IndexOutOfBoundsException: Index: 10, Size: 10 |
当时看到这个报错,真的是一脸懵逼,我代码看起来好像没有错误啊。那是哪里的原因,顺着代码一行行读,主要是发现数组越界:10。是不是因为我们size++
比如第 10 个 Thread 将 size 加到了 10,但是我们的 arrayList 最大也就为 9。那好像是会出现是问题哦,代码越界判断的习惯真的要注意。然后改了下代码v2版本:
1 |
|
然后再运行 main
方法就发现正常了。
1 | producer-1,生产数字:8 |
这样改了之后看起来好像是可以了。但总觉得哪里不对,可又说不出哪里的问题。