基于项目的学习使用
项目中使用这个线程池是Spring提供的,支持异步和定时.当前内部持有一个Java的线程池对象ThreadPoolExecutor
//这个线程池继承了AsyncListenableTaskExecutor,SchedulingTaskExecutor 所以支持异步和定时
public class ThreadPoolTaskExecutor extends ExecutorConfigurationSupport
implements AsyncListenableTaskExecutor, SchedulingTaskExecutor {
//加锁对象
private final Object poolSizeMonitor = new Object();
//核心线程数,默认值为1
private int corePoolSize = 1;
//最大线程数
private int maxPoolSize = Integer.MAX_VALUE;
//非核心线程存活时间,默认60s
private int keepAliveSeconds = 60;
//阻塞队列容量
private int queueCapacity = Integer.MAX_VALUE;
//是否允许线程超时
private boolean allowCoreThreadTimeOut = false;
//TaskDecorator是一个执行回调方法的装饰器,主要应用于传递上下文,或者提供任务的监控/统计信息。
@Nullable
private TaskDecorator taskDecorator;
//真正的线程池
@Nullable
private ThreadPoolExecutor threadPoolExecutor;
//存储运行任务集合
private final Map<Runnable, Object> decoratedTaskMap =
new ConcurrentReferenceHashMap<>(16, ConcurrentReferenceHashMap.ReferenceType.WEAK);
}
/**
* 这里配置线程池,主要用来执行异步/定时任务
*/
@Configuration
public class AsyncThreadPoolTaskConfig {
private static int cpuNums = Runtime.getRuntime().availableProcessors();
private static final int COREPOOLSIZE = cpuNums; // 核心线程数(默认线程数)
private static final int MAXPOOLSIZE = cpuNums * 5; // 最大线程数
private static final int KEEPALIVETIME = 5; // 允许线程空闲时间(单位:默认为秒)
private static final int QUEUECAPACITY = cpuNums * 100; // 缓冲队列数
private static final String THREADNAMEPREFIX = "AsyncTask-"; // 线程池名前缀
@Bean("taskExecutor") // bean的名称,默认为首字母小写的方法名
public ThreadPoolTaskExecutor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(COREPOOLSIZE);
executor.setMaxPoolSize(MAXPOOLSIZE);
executor.setQueueCapacity(QUEUECAPACITY);
executor.setKeepAliveSeconds(KEEPALIVETIME);
executor.setThreadNamePrefix(THREADNAMEPREFIX);
// 线程池对拒绝任务的处理策略
//这里使用的拒绝策略是CallerRunsPolicy,使用调用者的线程执行异步任务
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 初始化
executor.initialize();
return executor;
}
}
//定时清理90天之前的历史 热点关键词数据
@Component
@Transactional
public class HotKeywordScheduler extends JpaHibernateRepository {
@Autowired
private HotSearchKeyWordRepository repository;
@Async("taskExecutor")//使用线程池 启动
@Scheduled(cron="0 0 0 * * ?")
public void deletePastHotKeyword(){
repository.deletePastHotKeyword();
}
}
public void deletePastHotKeyword() {
Map<String,Object> params=new HashMap<String,Object>();
Date date=CalendarUtils.patchDateToDayStart(CalendarUtils.offsetMonths(new Date(), -3));
String sql = "delete from t_hot_search_keyword where create_time<= :dateTime";
params.put("dateTime", date);
this.createSQLQueryByMapParams(sql, params).executeUpdate();
}
private String lockType_clearSysMsg="clearSysMsg";
@Async("taskExecutor")//使用线程池 启动
@Scheduled(cron = "0 30 0,12 * * ?")
public void clearSysMsg() {
logger.info("---------定时清理系统消息begin------------");
boolean added=lockService.addLock(lockType_clearSysMsg,60);
if(!added) return;
try {
jpaBaseQueryService.createSqlQuery(
"delete from t_sys_msg where create_time<:comDate",
Utils.buildMap("comDate",CalendarUtils.offsetMinutes(new Date(),-30))
)
.executeUpdate()
;
}catch (Exception e) {
logger.error("---------定时清理系统消息出错------------",e);
}finally {
lockService.deleteLock(lockType_clearSysMsg);
}
logger.info("---------定时清理系统消息end------------");
}
@Entity
@Table(name = "t_locker")
public class ExcludeLock {
@Id
@Column(length = 200)
private String lockType;
private Date createTime = new Date();
private Date lastUpdate = new Date();
public ExcludeLock(String lockType, Date createTime) {
super();
this.lockType = lockType;
this.createTime = createTime;
}
public ExcludeLock() {
super();
}
public String getLockType() {
return lockType;
}
public Date getCreateTime() {
return createTime;
}
public Date getLastUpdate() {
return lastUpdate;
}
public void updateLastUpdate() {
this.lastUpdate = new Date();
}
}
@Repository
@SuppressWarnings("unchecked")
public class ExcludeLockJpaHibernateRepository extends JpaHibernateRepository {
public ExcludeLock excludeLock(String lockType) {
// 先以数据库行锁排除并发问题
ExcludeLock lock = null;
List<ExcludeLock> locks = this.createHQLQueryByParams(
"select o from " + ExcludeLock.class.getName()
+ " o where o.lockType=?0", lockType).list();
if (locks.isEmpty()) {
lock = new ExcludeLock(lockType, new Date());
this.getSession().save(lock);
this.getSession().flush();
} else {
lock = locks.get(0);
lock.updateLastUpdate(this);
//BUG:只有在数据中已存在的情况下才需要refresh,新增不允许
// 获得行级排他锁
this.getSession().refresh(lock, LockOptions.UPGRADE);
}
return lock;
}
public void update(ExcludeLock excludeLock) {
this.getSession().update(excludeLock);
this.getSession().flush();
}
private boolean isExistLock(String lockType) {
List<Object> rows = this.createSQLQueryByParams("select lock_type from t_locker where lock_type=?0 ",
lockType).list();
return rows.size() > 0 && rows.get(0) != null;
}
@Transactional
public boolean createLock(String lockType, Integer minutes) {
//删除 超时 为删除的锁 因为数据库锁 当时使用完就会删除 如果未删除 肯定有bug 此处强制清理超时1小时的锁
this.cleanExpiredLock(lockType, minutes);
if (this.isExistLock(lockType)) {
return false;
} else {
try {
ExcludeLock lock = new ExcludeLock(lockType, new Date());
this.getSession().save(lock);
this.getSession().flush();
return true;
} catch (Exception e) {
logger.error("占用锁[" + lockType + "]时发生错误:" + e.getMessage());
return false;
}
}
}
public void deleteLock(String lockType) {
List<ExcludeLock> locks = this.createHQLQueryByParams(
"select o from " + ExcludeLock.class.getName() + " o where o.lockType=?0", lockType
).list();
if (CollectionUtils.isNotEmpty(locks)) {
for (ExcludeLock lock : locks) {
this.getSession().delete(lock);
}
} else {//做兼容 删除
this.createSQLQueryByParams("delete from t_locker where lock_type=?0", lockType).executeUpdate();
}
this.getSession().flush();
}
public void cleanExpiredLock(String lockType, Integer minutes) {
//删除 创建时间 超过hours小时的锁 默认24小时
Date date = null;
if (minutes == null) minutes = -24 * 60;
if (minutes > 0) minutes = -minutes;
date = CalendarUtils.offsetMinutes(new Date(), minutes);
if (StringUtils.isBlank(lockType)) {
List<ExcludeLock> locks = this.createHQLQueryByParams(
"select o from " + ExcludeLock.class.getName() +
" o where o.createTime0 and o.lastUpdate is null",
date
).list();
for (ExcludeLock lock : locks) {
this.getSession().delete(lock);
}
//BUG:如果通过sql删除,再调用excludeLock,则会造成重复创建同一个lockType的锁对象
//this.createSQLQueryByParams("delete from t_locker where create_time0 and last_update is null",date).executeUpdate();
} else {
List<ExcludeLock> locks = this.createHQLQueryByParams(
"select o from " + ExcludeLock.class.getName() +
" o where o.createTime0 and o.lockType=?1",
date, lockType
).list();
for (ExcludeLock lock : locks) {
this.getSession().delete(lock);
}
//BUG:如果通过sql删除,再调用excludeLock,则会造成重复创建同一个lockType的锁对象
//this.createSQLQueryByParams("delete from t_locker where create_time0 and lock_type=?1",date,lockType).executeUpdate();
}
this.getSession().flush();
}
}
线程池其实是一种池化技术的实现,池化技术的核心思想其实就是实现资源的一个复用,避免资源的重复创建和销毁带来的性能开销。在线程池中,线程池可以管理一堆线程,让线程执行完任务之后不会进行销毁,而是继续去处理其它线程已经提交的任务。
降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统 的稳定性,使用线程池可以进行统一的分配,调优和监控。
线程在线程池内部被封装成了Worker对象
private final class Worker
extends AbstractQueuedSynchronizer
implements Runnable{
public void run() {
runWorker(this);
}
}
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
//重复利用的原因是因为这里使用while循环,只要有任务就会一直执行下去
while (task != null || (task = getTask()) != null) {
w.lock();
// If pool is stopping, ensure thread is interrupted;
// if not, ensure thread is not interrupted. This
// requires a recheck in second case to deal with
// shutdownNow race while clearing interrupt
if ((runStateAtLeast(ctl.get(), STOP) ||
(Thread.interrupted() &&
runStateAtLeast(ctl.get(), STOP))) &&
!wt.isInterrupted())
wt.interrupt();
try {
beforeExecute(wt, task);
Throwable thrown = null;
try {
task.run();
} catch (RuntimeException x) {
thrown = x; throw x;
} catch (Error x) {
thrown = x; throw x;
} catch (Throwable x) {
thrown = x; throw new Error(x);
} finally {
afterExecute(task, thrown);
}
} finally {
task = null;
w.completedTasks++;
w.unlock();
}
}
completedAbruptly = false;
} finally {
//如果获取不到任务则退回
processWorkerExit(w, completedAbruptly);
}
}
private Runnable getTask() {
boolean timedOut = false; // Did the last poll() time out?
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
// Check if queue empty only if necessary.
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
decrementWorkerCount();
return null;
}
int wc = workerCountOf(c);
// 是否超时判断
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {
if (compareAndDecrementWorkerCount(c))
return null;
continue;
}
try {
//如果超时则调用poll方法,否则调用take方法
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
if (r != null)
return r;
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
}
}
就是判断当前获取任务的线程是否可以超时退出的时候,如果将allowCoreThreadTimeOut设置为true,那么所有线程走到这个timed都是true,那么所有的线程,包括核心线程都可以做到超时退出。如果你的线程池需要将核心线程超时退出,那么可以通过allowCoreThreadTimeOut方法将allowCoreThreadTimeOut变量设置为true。
private static final int RUNNING = -1 << COUNT_BITS;
private static final int SHUTDOWN = 0 << COUNT_BITS;
private static final int STOP = 1 << COUNT_BITS;
private static final int TIDYING = 2 << COUNT_BITS;
private static final int TERMINATED = 3 << COUNT_BITS;
//存储状态的变量
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));