阻塞队列理论以及使用

在多线程领域,所谓阻塞,在某些情况下会挂起线程(即阻塞),一旦满足条件,被挂起的线程又会自动被唤醒。

为什么需要BlockingQueue?
好处是我们不需要关心什么时候需要阻塞线程,什么时候需要唤醒线程,因为这一切BlockingQueue已经做好阻塞的控制。

1.队列类型

黄色标记的是重点!!!

  1. ArrayBlockingQueue:由数组结构组成的有界阻塞队列。
  2. inkedBlockingQueue:有链表结构组成的队列,默认大小=为,Integer.MAX_VALUE。
  3. PriorityBlockingQueue:支持优先级排序的无界对列。
  4. DelayQueue:使用优先级队列实现的延迟无界队列。
  5. SynchronousQueue:不存储元素的阻塞队列,也即单个元素的队列。
  6. LinkedTransferQueue:由链表结构组成的无界阻塞队列。
  7. LinkedBlockingDeque:由链表结构组成的双向阻塞队列。
方法类型 抛出异常 特殊值 阻塞 超时
插入 add(e) offer(e) put(e) offer(e, time, unit)
移除 remove() poll() take() poll(time, unit)
检查 element() peek() 不可用 不可用
抛出异常 当阻塞队列满时,再往队列里add插入元素就会抛 IIlegalStateException 异常
当阻塞队列空时,再往队列里remove插入元素会抛 NoSuchElementException 异常
特殊值 插入方法,成功true失败false
移除方法,成功返回出队列的元素,队里里面没有就返回null
一直阻塞 当阻塞队列满时,生产者线程继续往队列里put元素,队列会一直阻塞生产者线程直到put数据or响应中断退出
当阻塞队列空时,消费者线程试图从队列里take元素,队列会一直阻塞消费者线程直到队列可用。
超时退出 当阻塞队列满时,队列会阻塞生产者线程一定时间,超时后生产者线程退出
当阻塞队列空时,队列会阻塞消费者线程一定时间,超时后消费者线程退出

2. SynchronousQueue

SynchronousQueue没有容量


与其他BlockingQueue不同,SynchronousQueue是一个不存储元素的BlockingQueue。

每个put操作必须等待一个take操作,否则不能继续添加元素,反正依然。

public class SynchronousQueueDemo {

	public static void main(String[] args) {
		BlockingQueue<Integer> blockingQueue = new SynchronousQueue<>();
		
		new Thread(() -> {
			try {
				System.out.println(Thread.currentThread().getName() + "\t put1");
				blockingQueue.put(1);
				
				System.out.println(Thread.currentThread().getName() + "\t put2");
				blockingQueue.put(2);
				
				System.out.println(Thread.currentThread().getName() + "\t put3");
				blockingQueue.put(3);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}).start();
		
		new Thread(() -> {
			try {
				Integer take = blockingQueue.take();
				System.out.println(Thread.currentThread().getName() + "\t" + take);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}).start();;
	}
	
}

阻塞队列理论以及使用_第1张图片


3.生产者消费者问题

/**
 * 资源类
 */
class ShareData {
	
	private int number = 0;
	private Lock lock = new ReentrantLock();
	
	private Condition condition = lock.newCondition();
	
	public void increment() throws Exception {
		lock.lock();
		try {
			while (number != 0) {
				condition.await();
			}
			number++;
			System.out.println(Thread.currentThread().getName() + "\t" + number);
			condition.signalAll();
		} finally {
			lock.unlock();
		}
	}
	
	public void decrement() throws Exception {
		lock.lock();
		try {
			while (number == 0) {
				condition.await();
			}
			number--;
			System.out.println(Thread.currentThread().getName() + "\t" + number);
			condition.signalAll();
		} finally {
			lock.unlock();
		}
	}
}

public class ProducerConsumerTXDemo {

	public static void main(String[] args) {
		final ShareData shareData = new ShareData();
		
		for (int i = 0; i < 5; i++) {
			new Thread(new Runnable() {
				@Override
				public void run() {
					try {
						for (int k = 0; k < 3; k++) {
							shareData.increment();
						}
					} catch (Exception e) {
					}
				}
			}, "P" + i).start();
		}
		
		for (int i = 0; i < 3; i++) {
			new Thread(new Runnable() {
				@Override
				public void run() {
					try {
						for (int k = 0; k < 5; k++) {
							shareData.decrement();
						}
					} catch (Exception e) {
					}
				}
			}, "C" + i).start();
		}
	}
}

用BlockingQueue做生产者消费者

class MyResource {
	
	// 默认开启进行生产
	private volatile boolean FLAG = true;
	
	// 用来记录生产个数
	private AtomicInteger atomicInteger = new AtomicInteger();
	
	private BlockingQueue<String> blockingQueue;
	
	public MyResource(BlockingQueue<String> blockingQueue) {
		this.blockingQueue = blockingQueue;
		System.out.println(blockingQueue.getClass().getName());
	}
	
	public void increment() throws Exception {
		String data = null;
		boolean resultVal = false;
		while (FLAG) {
			// 生产+1
			data = String.valueOf(atomicInteger.incrementAndGet());
			resultVal = blockingQueue.offer(data, 2L, TimeUnit.SECONDS);
			if (resultVal) {
				System.out.println(Thread.currentThread().getName() + "\t 插入队列成功!data:" + data);
			} else {
				System.out.println(Thread.currentThread().getName() + "\t 插入队列失败!data:" + data);
			}
			Thread.sleep(1000);
		}
		System.out.println("生产停止");
	}
	
	public void decrement() throws Exception {
		while (FLAG) {
			String data = blockingQueue.poll(2L, TimeUnit.SECONDS);
			if (data != null) {
				System.out.println(Thread.currentThread().getName() + "\t 消费队列成功!data:" + data);
			}
		}
		System.out.println("消费停止");
	}
	
	public void interrupt() {
		System.out.println("程序中断!!");
		this.FLAG = false;
	}
}

public class ProducerConsumerBlockingDemo {

	public static void main(String[] args) throws Exception {
		final MyResource myResource = new MyResource(new ArrayBlockingQueue<>(1));
		
		for (int i = 0; i < 5; i++) {
			new Thread(new Runnable() {
				@Override
				public void run() {
					try {
						for (int k = 0; k < 3; k++) {
							myResource.increment();
						}
					} catch (Exception e) {
					}
				}
			}, "P" + i).start();
		}
		
		for (int i = 0; i < 3; i++) {
			new Thread(new Runnable() {
				@Override
				public void run() {
					try {
						for (int k = 0; k < 5; k++) {
							myResource.decrement();
						}
					} catch (Exception e) {
					}
				}
			}, "C" + i).start();
		}
		
		
		Thread.sleep(3 * 1000);
		System.out.println("==============================");
		myResource.interrupt();
	}
}

你可能感兴趣的:(面试,java)