Condition and use ReentrantLock with the realization of blocking queue

After learning ReentrantLock Condition and today, found that the use ReentrantLock Condition and used in conjunction with each other communication between threads is more flexible than wait and notify methods Object. I wrote a small example to deepen the image: _

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");
	}
}
Published 548 original articles · won praise 3338 · Views 2.6 million +

Guess you like

Origin blog.csdn.net/dataiyangu/article/details/105040495