java 阻塞队列和线程池的使用

阻塞队列:import java.util.concurrent.BlockingQueue;

线程池:import java.util.concurrent.ExecutorService;

初始化队列和线程池:

package com.gxhc.alarm.listener;

import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

import com.gxhc.alarm.service.AlarmService;
import com.gxhc.alarm.listener.QueueWatcher;
import com.gxhc.util.ConstantUtil;
import com.gxhc.util.ContextUtil;

public class QueueListener implements ServletContextListener {

	/**
	 * 初始化加载
	 */
	@Override
	public void contextInitialized(ServletContextEvent arg0) {
		setQueue();
		setWatcher();
		setFixedThreadPool();
	}
	
	//初始化队列
	public void setQueue(){
		ConstantUtil.alarmQueue = new LinkedBlockingQueue<Object>(10000);
	}

	//初始化被观察者
	public void setWatcher(){
		//modify by sl 原来的被观察者,不是上下文中的alarmService ,无法触发观察者事件
		//ConstantUtil.alarmService = new AlarmService();
		ConstantUtil.alarmService = ContextUtil.getBean("alarmService",AlarmService.class);
		QueueWatcher queueWatcher = new QueueWatcher(ConstantUtil.alarmService);
	}
	
	//初始化线程池
	public void setFixedThreadPool(){
		// 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
		ConstantUtil.alarmFixedThreadPool = Executors.newFixedThreadPool(10); 
	}
	@Override
	public void contextDestroyed(ServletContextEvent arg0) {
	}
}

第一次,触发观察者,启动队列线程,当阻塞队列中无数据时,该线程会进入阻塞状态,直到队列中有数据,才会变成运行状态;

package com.gxhc.alarm.listener;

import java.util.Map;
import java.util.Observable;
import java.util.Observer;

import com.gxhc.alarm.service.AlarmService;
import com.gxhc.alarm.table.entity.AlarmLog;
import com.gxhc.util.ConstantUtil;
import com.gxhc.util.ContextUtil;

public class QueueWatcher implements Observer{
	
    public QueueWatcher(Observable o){
        o.addObserver(this);
    }
    
    public QueueWatcher(){}
    
    
    
        /* (非 Javadoc)
        * 
        * 观察者只被触发一次,后续消息的推送由队列维护
        * @param o 被观察者
        * @param arg
        * @see java.util.Observer#update(java.util.Observable, java.lang.Object)
        */
        
    @Override
    public void update(Observable o, Object arg) {
    	//通过定长java线程池执行该操作,防止无限启动线程导致程序卡死。
    	ConstantUtil.alarmFixedThreadPool.execute(new Runnable() {
			
			@Override
			public void run() {
				try {
					// TODO Auto-generated method stub
					ConstantUtil.IsGeginQueue = true;
					
					AlarmService alarmService = ContextUtil.getBean("alarmService",AlarmService.class);
					while (ConstantUtil.IsGeginQueue) {
						//如果阻塞队列中无元素可取,则线程进入阻塞状态,直到该队列中再次拥有元素时,激活。
						//AlarmLog alarmLog = (AlarmLog)ConstantUtil.alarmQueue.take();
						Map<String, Object> map = (Map<String, Object>)ConstantUtil.alarmQueue.take();
						alarmService.insertMessage((AlarmLog)map.get("alarmLog"),String.valueOf(map.get("reciveUser")),String.valueOf(map.get("reciverDept")),String.valueOf(map.get("cid")));
					}
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		});
    	
    	
    	
		/*ConstantUtil.alarmFixedThreadPool.execute(new Runnable() {
			
			@Override
			public void run() {
				try {
					AlarmLog alarmLog = (AlarmLog)ConstantUtil.alarmQueue.take();
					AlarmService alarmService = ContextUtil.getBean("alarmService",AlarmService.class);
					// TODO Auto-generated method stub
					alarmService.setMessage(alarmLog,null,null);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		});*/
		
		// 触发订阅处理
		//alarmService.setMessage(((AlarmService)o).getAlarmLog(),null,null);
		
    }

}

所以,当启动队列线程后,不用再次启动,后续消息的推送,只需要往队列里放数据就行了。

 

/*******************************************关于阻塞队列的拓展***************************************************************/

 

1.阻塞队列

在阻塞队列中有生产者和消费者的概念,生产者往队列中放数据,而消费者负责消费(即使用和从队列中移除)产品。

当队列中元素已经满的时候,生产产品的线程会被阻塞,当队列中无元素时,消费产品的线程会被阻塞。

当再次满足上述条件时,对应的线程又会被再次唤醒。

1.1 JDK提供的阻塞队列:

    ArrayBlockingQueue:一个由数组结构组成的有界阻塞队列,遵循FIFO原则。

    LinkedBlockingQueue:一个由链表结构组成的有界阻塞队列,遵循FIFO原则,默认和最大长度Integer.MAX_VALUE。

    PriorityBlockingQueue:一个支持优先级排序的无界阻塞队列。

    DelayQueue:一个使用优先级队列实现的无界阻塞队列。

    SynchronousQueue:一个不存储元素的阻塞队列。

    LinkedTransferQueue:一个由链表结构组成的无界阻塞队列。

    LinkedBlockingDeque:一个由链表结构组成的双向阻塞队列。

 

1.2 BlockingQueue中API介绍

offer(E e): 将给定的元素设置到队列中,如果设置成功返回true, 否则返回false. e的值不能为空,否则抛出空指针异常。

offer(E e, long timeout, TimeUnit unit): 将给定元素在给定的时间内设置到队列中,如果设置成功返回true, 否则返回false.

add(E e): 将给定元素设置到队列中,如果设置成功返回true, 否则抛出异常。如果是往限定了长度的队列中设置值,推荐使用offer()方法。

put(E e): 将元素设置到队列中,如果队列中没有多余的空间,该方法会一直阻塞,直到队列中有多余的空间。

take(): 从队列中获取值,如果队列中没有值,线程会一直阻塞,直到队列中有值,并且该方法取得了该值。

poll(long timeout, TimeUnit unit): 在给定的时间里,从队列中获取值,如果没有取到会抛出异常。

remainingCapacity():获取队列中剩余的空间。

remove(Object o): 从队列中移除指定的值。

contains(Object o): 判断队列中是否拥有该值。

drainTo(Collection c): 将队列中值,全部移除,并发设置到给定的集合中

 

/****************************************关于线程池的拓展***********************************************/

创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。

ExecutorService alarmFixedThreadPool = Executors.newFixedThreadPool(10); 

 

参考:https://www.cnblogs.com/zhaoyan001/p/7049627.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值