阻塞队列ArrayBlockingQueue说明

本文详细介绍了阻塞队列的基本概念及其在Java中的应用,包括线程状态转换、阻塞队列的工作原理以及通过具体代码实现的生产者与消费者模式。并通过实例展示了如何利用阻塞队列来实现线程间的同步。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 什么是阻塞队列

对于共享数据,线程A想读取的队列中没有数据时,处于阻塞状态。直接线程B将数据写入共享数据,线程被唤醒。


2.参考如下博客的线程状态转换图和状态说明,自己也做个收藏(来自:https://my.oschina.net/mingdongcheng/blog/139263)


线程间的状态转换: 

1. 新建(new):新创建了一个线程对象。

2. 可运行(runnable):线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取cpu 的使用权 。

3. 运行(running):可运行状态(runnable)的线程获得了cpu 时间片(timeslice) ,执行程序代码。

4. 阻塞(block):阻塞状态是指线程因为某种原因放弃了cpu 使用权,也即让出了cpu timeslice,暂时停止运行。直到线程进入可运行(runnable)状态,才有机会再次获得cpu timeslice 转到运行(running)状态。阻塞的情况分三种: 

(一). 等待阻塞:运行(running)的线程执行o.wait()方法,JVM会把该线程放入等待队列(waitting queue)中。

(二). 同步阻塞:运行(running)的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池(lock pool)中。

(三). 其他阻塞:运行(running)的线程执行Thread.sleep(long ms)或t.join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入可运行(runnable)状态。

5. 死亡(dead):线程run()、main() 方法执行结束,或者因异常退出了run()方法,则该线程结束生命周期。死亡的线程不可再次复生。

(来自:https://my.oschina.net/mingdongcheng/blog/139263)


3. 阻塞队列代码实践

1)阻塞队列不停的有数据写入,发送线程不停从队列读取数据,直到标志位置为true。

package com.sean.test;

import java.util.concurrent.ArrayBlockingQueue;

public class SendMessageProcess implements Runnable
{
	private static ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<String>(9);

	public static ArrayBlockingQueue getQueue()
	{
		return queue;
	}

	public static void setQueue(ArrayBlockingQueue queue)
	{
		SendMessageProcess.queue = queue;
	}
	
	public boolean isExit()
	{
		return exit;
	}

	public void setExit(boolean exit) 
	{
		this.exit = exit;
	}

	private boolean exit = false;

	@Override
	public void run() 
	{
		while (!exit)
		{
			System.out.println("begin SendMessageProcess run().and the exit is:" + exit) ;
			String s = null;
			try 
			{
				s = queue.take();
				System.out.println("end SendMessageProcess run()." + s);
			} 
			catch (InterruptedException e)
			{
				e.printStackTrace();
			}
		}
	}
	
	public void quit() throws InterruptedException
	{
		queue.put("end the process");
		exit = true;
	}
}

2)主线程往队列里写入数据,新起一个定时任务,过3s时间将标志位置为true。为了保证阻塞线程唤醒启动,在标志位置位的时候往队列新写入一个字符数据。
否则线程一直处于阻塞状态,线程挂死。
package com.sean.test;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class SeanTest 
{
	private static ScheduledExecutorService service = null;
	
	public static void main(String[] args) throws InterruptedException 
	{
		SendMessageProcess process = new SendMessageProcess();
		SendMessageProcess.getQueue().put("test1");
		SendMessageProcess.getQueue().put("test2");
		service = Executors.newSingleThreadScheduledExecutor(); 
		service.schedule(new newTask(process), 3, TimeUnit.SECONDS);	
		process.run();
	}
	
	public static class newTask implements Runnable
	{
		SendMessageProcess process = null;
		public newTask(SendMessageProcess process)
		{
			this.process = process;
		}

		@Override
		public void run() 
		{
			System.out.println("Begin newTask run()");
			try 
			{
				process.quit();
			} 
			catch (InterruptedException e) 
			{
				e.printStackTrace();
			}
			System.out.println("End newTask run().exit:" + process.isExit());
			service.shutdown();
		}
	}
}

4. 阻塞队列在java中适合使用生产者、消费者场景。为了唤醒消费者,需要生产者往队列写入数据。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值