今天学习了 ReentrantLock 和 Condition之后, 发现使用 ReentrantLock 和 Condition 配合使用实现线程间的相互通信比Object的wait和notify方法更灵活。写了一个小例子加深映象:_
package com.jack.jucstudy;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* 模拟一个阻塞队列,实现如下功能:
* 1、拥有固定长度可盛装容器
* 2、计数器统计容器容量大小
* 3、当队列里没有元素的时候,取元素的线程需要等待
* 4、当队列里的元素已满时,存元素的线程需要等待
* @author Teng
*
*/
public class MyBlockingQueue<E>{
//随便定义一个容器用来保存数据
private final List<E> list = new ArrayList<>();
//重入锁
private final Lock lock = new ReentrantLock();
//Condition与lock配合使用,来操作线程之间的等待与唤醒
private final Condition condition = lock.newCondition();
//队列中元素的个数
private final AtomicInteger count = new AtomicInteger(0);
private final int MAX_SIZE;
private final int MIN_SIZE = 0;
public MyBlockingQueue(int maxSize) {
this.MAX_SIZE = maxSize;
}
/**
* 向队列中放入元素,
* 如果队列已满,则阻塞,等待被condition唤醒,await()方法会释放锁
* 如果成功放入元素,则通知其他可能等待的线程,signal()方法不释放锁
* @param object
*/
public void put(E object) {
lock.lock();
try {
if(count.get() == MAX_SIZE) {
condition.await();
System.out.println("阻塞线程被唤醒了");
}
list.add(object);
count.getAndIncrement();
System.out.println(String.format("向队列中添加了一个元素%s", object));
condition.signal();
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
/**
* 从队列中取出元素,
* 如果队列是空的,则阻塞等待被其他线程唤醒
* 如果取值成功,则唤醒其他线程
* @return
*/
public E take() {
E object = null;
lock.lock();
try {
if(count.get() == MIN_SIZE) {
condition.await();
}
object = list.get(0);
System.out.println(String.format("从队列中取出一个元素%s", object));
count.decrementAndGet();
condition.signal();
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
return object;
}
/**
* 获取队列中元素的方法
* @return
*/
public int getSize() {
return count.get();
}
public static void main(String[] args) {
MyBlockingQueue<String> myQueue = new MyBlockingQueue<>(5);
new Thread(new Runnable() {
@Override
public void run() {
myQueue.take();//此时队列中没有元素,线程阻塞
}
},"t1").start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
myQueue.put("a");//此时可以去唤醒t1线程了
myQueue.put("b");
myQueue.put("c");
myQueue.put("d");
myQueue.put("e");
myQueue.put("f");
}
}