线程轮询的有数据启动,无数据停止,节省服务器资源,线程的启动和暂停

2 篇文章 0 订阅
2 篇文章 0 订阅

现实场景有这样一个需求:

某工作大厅,有几百个工作人员,当有某个工作人员向离岗出去,要点击自己工位上的暂离按钮,回岗的时候点击工位上的回岗按钮,如果离岗超过20分钟还没有回岗则短信提醒该工作人员离岗超时,该回岗了!

我们需要怎么处理这个业务呢?

首先要有一个缓存Map,存放工作人员的userid和超时时间。

然后针对该Map提供数据删除和添加的方法,回岗就删除,离岗就添加。

最后再起一个线程一直轮询该Map,当前时间和Map中的超时时间做对比,如果当前时间在超时时间之后,那这个人就是超时了,然后进行短信提醒。

 

先看一下这个缓存的Map,我这里写了一个工具类:

 

/**
 * 检测用户离岗是否超时工具类
 * @author Run the ant
 * @date 2018年8月2日
 * @version 1.0
 */
@Service
public class BackJobCheckUtil {
	private final static Logger logger = LoggerFactory.getLogger(BackJobCheckUtil.class);
	
	public static final String NAMESPACE = "backjobcheck";
	public static final String DATAKEY = "datakey";
	
	@Autowired
	private BackJobCheckTask backJobCheckTask;

	@Resource(name = "cache")
	private BaseCache<HashMap<String, Date>> datecache;
	
	/**
	 * 确认是否有人员暂离超时(超时发送短信,但是只会发送一次)
	 * 
	 * @author Run the ant
	 * @data 2018年8月2日
	 */
	public void check () {
		HashMap<String, Date> data = getDataCache();
		if (data.size() == IConstant.ZERO) {
			//当查询到缓存中没有数据的时候则中断该任务
			backJobCheckTask.interrupt();
		}
		Date now = DateUtil.getCurrentDate();
		List<String> uids = new ArrayList<String>();
		for (Entry<String, Date> entry : data.entrySet()) {
			Date date = entry.getValue();
			//如果离岗时间超出限制则短信提醒
			if (now.after(date)) {
				//短信提醒业务
			}
		}
		if (uids.size() > 0) {
			for (String uid : uids) {
				data.remove(uid);
			}
			datecache.put(NAMESPACE, DATAKEY, data);
		}
	}
	
	/**
	 * 添加一条人员离岗记录
	 * @param uid
	 * @author Run the ant
	 * @data 2018年8月2日
	 */
	public synchronized void addUserOverTime (String uid) {
		Integer overmin = 20;
		Date overtime = new Date(new Date().getTime() + overmin * 60 * 1000);
		HashMap<String, Date> data = getDataCache();
		data.put(uid, overtime);
		datecache.put(NAMESPACE, DATAKEY, data);
		//唤醒
		backJobCheckTask.build();
	}
	
	/**
	 * 删除一条人员离岗记录
	 * @param uid
	 * @author Run the ant
	 * @data 2018年8月2日
	 */
	public synchronized void delUserOverTime (String uid) {
		HashMap<String, Date> data = getDataCache();
		data.remove(uid);
		datecache.put(NAMESPACE, DATAKEY, data);
	}
	
	
	/**
	 * 获取缓存中的人员超时时间数据
	 * @return
	 * @author Run the ant
	 * @data 2018年8月2日
	 */
	private HashMap<String, Date> getDataCache () {
        //针对自己的缓存修改代码,业务都是这样,从缓存取出我的Map数据
		HashMap<String, Date> data = datecache.get(NAMESPACE, DATAKEY);
		if (data == null) {
			data = new HashMap<String, Date>();
			datecache.put(NAMESPACE, DATAKEY, data);
		}
		return data;
	}
	
}

这里有BackJobCheckTask这个类,这个是线程执行的类,贴代码:

/**
 * 检测用户离岗是否超时任务
 * @author Run the ant
 * @date 2018年7月31日
 * @version 1.0
 */
@Service
public class BackJobCheckTask implements Runnable {

	@Autowired
	private BackJobCheckUtil backJobCheckUtil;
	
	private ReentrantLock lock = new ReentrantLock();
    private final static Logger logger = LoggerFactory.getLogger(BackJobCheckTask.class);
    private Thread tempThread;
    private final static String name = "检测用户离岗是否超时任务";
    
    @Override
	public void run() {
		logger.info("线程【{}】开始运行", tempThread.getName());
		try {
			while (true) {
				backJobCheckUtil.check();
				tempThread.sleep(3000);
			}
		} catch (Exception e) {
			logger.error(name + "异常",e);
		}
		logger.info("线程【{}】停止运行", tempThread.getName());
	}
    
    
    /**
     * 检测线程是否启动,未启动则启动线程
     * 
     * @author Run the ant
     * @data 2018年7月31日
     */
    private void runThread(){
		if(tempThread == null || tempThread.isAlive() == false){
			try {
				lock.lock();
				if(tempThread == null || tempThread.isAlive() == false){
					tempThread = new Thread(this,name);
					tempThread.start();
				}
			} catch (Exception e) {
				logger.error("发布者{}线程启动失败", name,e);
			}finally{
				lock.unlock();
			}
		}
	}
    
    /**
     * 线程中断
     * 
     * @author Run the ant
     * @data 2018年7月31日
     */
    public void interrupt(){
		if(tempThread != null){
			tempThread.interrupt();
		}
	}
    
    /**
     * 线程唤醒
     * 
     * @author Run the ant
     * @data 2018年7月31日
     */
    public void build(){
		runThread();
	}

}

然后还需要1个接口,来接收工作人员点击暂离和回岗的消息:

@Controller
@RequestMapping(value={"/servlet"})
public class Servlet {
	private final static Logger logger = LoggerFactory.getLogger(Servlet .class);
	
    @Autowired
	private BackJobCheckUtil backJobCheckUtil;

	/**
	 * 暂离
	 * @param request
	 * @param response
	 * @param uid  窗口人员uid
	 * @author Run the ant
	 * @data 
	 */
	@ResponseBody 
	@RequestMapping(value = "/windowpause")
	public void windowPause (HttpServletRequest request, HttpServletResponse response, String uid) {
         //接口认证等等其他业务,自行修改
         backJobCheckUtil.addUserOverTime(uid);

	}
	
	/**
	 * 回岗
	 * @param request
	 * @param response
	 * @param uid 窗口人员uid
	 * @author Run the ant
	 * @data 
	@ResponseBody 
	@RequestMapping(value = "/windownormal")
	public void windowNormal (HttpServletRequest request, HttpServletResponse response, 
			String uid) {
        //接口认证等等其他业务,自行修改
		backJobCheckUtil.delUserOverTime(uid);
	}
	

}

 

OK,这样就实现了,当没有人暂离的时候,该线程就自行销毁,如果某个时间点突然有数据加入,线程就重新启动。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Run_the_ant

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值