前言
Lock锁相对于传统的synchronized关键字来说更加灵活,Lock锁为我们提供了显示加锁、可中断加锁、超时加锁等机制。
Lock锁 VS synchronized锁:
- 二则都是可重入锁
- synchronized是关键字,不会导致死锁,而Lock可能会出现死锁;
- synchronized不能响应中断,获取不到锁会一直阻塞,而Lock可以响应中断,可以知道是否获取了锁
- synchronized为独占锁,锁的获取和释放由JVM实现
实现阻塞队列
阻塞队列要点:
- 当队列中没有元素时就阻塞,有则返回元素;
- 当队列已满时阻塞,未满时将元素放入队列;
这里我们要结合使用JUC包下的Condition,对线程的阻塞与执行实现更加灵活的控制
实现如下:(建议在多线程下多测试几次,观察各个线程的加锁解锁过程)
public class CustomBlockingQueue {
// 这里我们用ArrayList模拟队列
private List<Object> queue = new ArrayList<>();
// 创建lock对象,同时创建两个condition实例,分别用于控制阻塞队列的读和写
private Lock lock = new ReentrantLock();
private Condition putCondition = lock.newCondition();
private Condition takeCondition = lock.newCondition();
// 阻塞队列的大小
private int size;
public CustomBlockingQueue(int size) {
this.size = size;
}
/**
* 向阻塞队列放入元素,如果队列已满则阻塞
*
* @param obj 放入队列的元素
*/
public void put(Object obj) {
lock.lock();
System.out.println(Thread.currentThread().getName() + " got the lock ... " + lock);
try {
while (true) {
// 如果队列未满,则放入元素
if (queue.size() < size) {
queue.add(obj);
System.out.println(Thread.currentThread().getName() + " add to queue: " + obj);
takeCondition.signal();
break;
} else {
// 队列已满,则阻塞
System.out.println(Thread.currentThread().getName() + " want to add a obj but queue is full...");
putCondition.await();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println(Thread.currentThread().getName() + " release the lock ... " + lock);
lock.unlock();
}
}
/**
* 从阻塞队列获取元素,如果队列为空则阻塞
*
* @return 获取的元素
*/
public Object take() {
lock.lock();
System.out.println(Thread.currentThread().getName() + " got the lock ... " + lock);
Object obj = null;
try {
while (true) {
// 如果队列不为空,则获取队头元素
if (queue.size() > 0) {
obj = queue.remove(0);
System.out.println(Thread.currentThread().getName() + " get a obj: " + obj);
putCondition.signal();
return obj;
} else {
// 队列为空,阻塞
System.out.println(Thread.currentThread().getName() + " want to get a obj but no one...");
takeCondition.await();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println(Thread.currentThread().getName() + " release the lock ... " + lock);
lock.unlock();
}
return obj;
}
}