首先我们实现一个阻塞式队列
需要考虑的问题:
- 队列采用什么存储: ArrayList
- 队列存取之间的通信方式:使用wait和notify
- 队列存取如何保准数据一致性问题:加锁synchronized
实现代码:
import java.util.ArrayList;
import java.util.List;
/**
* @author WH
* @version 1.0
* @date 2019/10/11 21:25
*/
public class BlockingQueue {
//队列使用ArrayList存储
List<String> list = new ArrayList<String>();
//对象锁
private Object lock = new Object();
//存储数据
public void put() {
synchronized (lock) {
for (int i = 0; i < 10; i++) {
list.add("jack");
System.out.println("线程添加了" + i);
if (list.size() == 6) {
//数据添加了6个,你可以来取了
lock.notify(); //发出通知,不释放锁
System.out.println("线程" + Thread.currentThread().getName() + "发出通知");
}
}
}
}
//取数据
public void get() {
synchronized (lock) {
System.out.println("线程" + Thread.currentThread().getName() + "进入等待");
try {
lock.wait();//进入等待,释放锁
} catch (InterruptedException e) {
e.printStackTrace();
}
for (String s : list) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("取出了元素" + s);
}
}
}
public static void main(String[] args) {
final BlockingQueue blockingQueue = new BlockingQueue();
new Thread(new Runnable() {
@Override
public void run() {
blockingQueue.get();
}
}, "T1").start();
//保证线程一线先执行
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(new Runnable() {
@Override
public void run() {
blockingQueue.put();
}
},"T2").start();
}
}
说明:线程一先执行:wait,释放锁,使线程一处于阻塞状态
线程二拿到锁执行,执行notify,但不释放锁,线程一被唤醒,拿不到锁,等待线程二执行完后释放锁,线程一继续执行
wait: 释放锁,是线程处于等待状态
notify:不释放锁,同时唤醒一个因使用了wait处于阻塞状态的线程,使其处于就绪状态,但需要重新获得锁才能执行
notifyAll:唤醒所有因使用了wait处于阻塞状态的线程