文档章节

具有相同属性任务串行有序执行的线程池设计

BlackJoker
 BlackJoker
发布于 2015/10/13 13:24
字数 411
阅读 28
收藏 0

我有一个这样的线程池的场景,相信很多人都遇到过: 
1,每个用户都可以添加多个任务; 
2,有很多的用户和很多的任务; 
3,每个用户添加的任务必须有序串行执行,即在同一时刻不能有同时执行一个用户的两个任务; 
4,实时性:只要线程池线程有空闲的,那么用户提交任务后必须立即执行;尽可能提高线程的利用率。 

代码比较简洁,基本满足上述要求:

public class SerialThreadExecutor {
	private Executor executor;
	private ConcurrentMap<Object, SequentialJob> serialJobs = new ConcurrentHashMap<Object, SequentialJob>();

	public SerialThreadExecutor(Executor executor) {
		super();
		this.executor = executor;
	}

	public void executeSerially(Object key, Runnable r) {
		SequentialJob job = serialJobs.get(key);
		if (job == null) {
			job = new SequentialJob(key);
			SequentialJob oldJob = serialJobs.put(key, job);
			if (oldJob != null) {
				job = oldJob;
			}
		}
		job.addJob(r);
	}

	private class SequentialJob implements Runnable {
		private BlockingQueue<Runnable> jobs = new LinkedBlockingQueue<Runnable>();
		private Object key;
		private AtomicBoolean running = new AtomicBoolean(false);

		public SequentialJob(Object key) {
			this.key = key;
		}

		public void run() {
			Runnable r = null;
			while (true) {
				try {
					r = jobs.poll(50, TimeUnit.MILLISECONDS);
					if (r != null) {
						r.run();
					} else {
						synchronized (this) {
							if (jobs.isEmpty()
									&& running.compareAndSet(true, false)) {
								return;
							} else {
								continue;
							}
						}
					}
				} catch (InterruptedException e) {
					// TODO
					e.printStackTrace();
				}
			}
		}

		public void addJob(Runnable r) {
			synchronized (this) {
				jobs.add(r);
				if (running.compareAndSet(false, true)) {
					executor.execute(this);
				}
			}
		}
	}
}

这个实现有几个缺陷:

1,每次添加一个任务都要进入一次锁,有一点小小开销;

2,serialJobs会一直在内存中,当某个key的任务很久没有添加了,对应的SequentialJob对象一直存在,虽然不占用很多内存,但对于有洁癖的人来说或,还是不爽。

 

抛砖引玉,看看广大网友是否可以优化。

(异常处理等细节大家就不要理会了)

 

© 著作权归作者所有

共有 人打赏支持
BlackJoker
粉丝 1
博文 17
码字总数 9270
作品 0
深圳
高级程序员
源码|从串行线程封闭到对象池、线程池

今天讲一个牛逼而实用的概念,。是串行线程封闭的典型应用场景;糅合了对象池技术,但核心实现不依赖于对象池,很容易产生误会。本文从串行线程封闭和对象池入手,最后通过源码分析线程池的核...

猴子007
2017/11/14
0
0
JAVA线程池以及队列拒绝策略

工作中遇到了消息队列的发送,之前都是用数据库作为中转和暂存的。这次考虑用多线程的方式进行消息的发送,于是学习了一下线程池的应用。说实话,实践中对Java高级特性的应用真的不多,对多线...

健康的程序员
2016/05/17
73
0
JAVA线程池学习以及队列拒绝策略

JAVA线程池学习以及队列拒绝策略 为什么要用线程池? 在Java中,如果每当一个请求到达就创建一个新线程,开销是相当大的。在实际使用中,每个请求创建新线程的服务器在创建和销毁线程上花费的...

DemonsI
09/02
0
0
Java并发编程之线程池必用知识点

再使用线程池之前,我们应该了解为什么需要使用线程池。进行执行任务(task)的时候我们一般情况是new Thread进行执行,如果进行大量的并发任务的时候呢? 大多数并发应用程序是围绕执行任务...

静默加载
2017/10/11
0
0
串行还是并行?——记一次 AsyncTask 问题排查

事情起源于一个bug排查,一个AsyncTask的子类,执行的时候发现onPreExecute方法执行了,doInBackground却迟迟没有被调用。 懂AsyncTask一些表面原理的都知道,onPreExecute方法是在主线程执行...

ZxLee
2017/03/04
0
0

没有更多内容

加载失败,请刷新页面

加载更多

arcgis jsapi接口入门系列:总览

开发环境: arcgis jsapi版本4.9 由于我们这套代码是基于vue,webpack开发的,会有少数vue代码,但总体不影响 里面还有些我们公司的js库和html css,给出的代码不能百分百直接运行,主要还是...

canneljls
1分钟前
0
0
月薪80k阿里架构师漫谈他是如何从一名小码农走到架构师的

01 刚当程序员时,我是属于那种勤勤恳恳类型的员工,工作态度用认真来形容不为过,每天我几乎是团队里最早到公司,又最晚下班的一个。而组员张工一般情况下都是准时上下班的,即使项目进度比...

Java填坑之路
3分钟前
0
0
oracle的resetlogs机制浅析

oracle的resetlogs机制浅析 alter database open resetlogs 这个命令我想大家都很熟悉了,那有没有想过这个resetlogs选项为什么要用?什么时候用? 它的原理机制是什么?他都起哪些作用? 我...

突突突酱
4分钟前
0
0
JAVA 获取两个日期间的所有日期

public static List<String> getDates(String startDate, String endDate){    Date d1 = new SimpleDateFormat("yyyyMMdd").parse(startDate);//定义起始日期    Date d2 = new Simple......

尘叙缘
11分钟前
0
0
Innodb中的事务隔离级别和锁的关系

#一次封锁or两段锁? 因为有大量的并发访问,为了预防死锁,一般应用中推荐使用一次封锁法,就是在方法的开始阶段,已经预先知道会用到哪些数据,然后全部锁住,在方法运行之后,再全部解锁。...

Skqing
25分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部