使用ReentrantLock和Condition配合实现阻塞队列

今天学习了 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");
	}
}
发布了548 篇原创文章 · 获赞 3338 · 访问量 260万+

猜你喜欢

转载自blog.csdn.net/dataiyangu/article/details/105040495