基础储备:
java.util.concurrent
类 Executors
java.lang.Object
继承者 java.util.concurrent.Executors
此类是个工具类,它提供对Executor、ExecutorService、ScheduledExecutorService、ThreadFactory 和 Callable 类的一些实用方法。
此类支持以下各种方法:
- 创建并返回设置有常用配置的ExecutorService的方法。
- 创建并返回设置有常用配置的ScheduledExecutorService 的方法。
- 创建并返回“包装的”ExecutorService方法,它使特定于实现的方法不可访问,只让ExecutorService接口的方法可用。
- 创建并返回 ThreadFactory的方法,它可将新创建的线程设置为已知的状态。
- 创建并返回非闭包形式的 Callable 的方法,这样可将其用于需要 Callable的执行方法中。
主要方法:
public static ExecutorService newFixedThreadPool(int nThreads)
创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程。 在任意点,在大多数 nThreads 线程会处于处理任务的活动状态。如果在所有线程处于活动状态时提交附加任务,则在有可用线程之前,附加任务将在队列中等待。如果在关闭前的执行期间由于失败而导致任何线程终止, 那么一个新线程将代替它执行后续的任务(如果需要)。在某个线程被显式地关闭之前,池中的线程将一直存在。
参数:
nThreads - 池中的线程数
返回:
新创建的线程池
抛出:
IllegalArgumentException - 如果 nThreads <= 0
注意:它的全是core线程。其源码如下:
return new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue());
public static ExecutorService newFixedThreadPool(int nThreads,ThreadFactory threadFactory)
创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程,在需要时使用提供的 ThreadFactory 创建新线程。在任意点,在大多数 nThreads 线程会处于处理任务的活动状态。如果在所有线程处于活动状态时提交附加任务,则在有可用线程之前,附加任务将在队列中等待。如果在关闭前的执行期间由于失败而导致任何线程终止,那么一个新线程将代替它执行后续的任务(如果需要)。在某个线程被显式地关闭之前,池中的线程将一直存在。
参数:
nThreads - 池中的线程数
threadFactory - 创建新线程时使用的工厂
返回:
新创建的线程池
抛出:
NullPointerException - 如果 threadFactory 为 null
IllegalArgumentException - 如果 nThreads <= 0
主代码:
package com.phhc.batchprocess.escapeservice.impl;
import com.phhc.audit.common.CacheTypeEnum;
import com.phhc.audit.common.DataEscapeExportModel;
import com.phhc.batchprocess.escapeservice.DataSourceUtil;
import com.phhc.cache.CustomerCacheLoading;
import com.phhc.core.log.LoggerFactory;
import com.phhc.data.DbHelperBase;
import com.phhc.dictescape.model.parameter.Prescription_base;
import com.phhc.thread.ThreadUtil;
import org.slf4j.Logger;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collection;
import java.util.Queue;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicLong;
/**
* 批量处方转义服务实现
* Created by dongzy on 2018/1/16.
*/
public class BatchPresEscapeServiceImpl {
//日志
private static final Logger LOGGER = LoggerFactory.getLogger("batchprocessResult", BatchPresEscapeServiceImpl.class);
private static Queue<Integer> ids;
private static String spBatchId;
private static String spId;
private static Integer idsCount;
private static AtomicLong idComplete = new AtomicLong();
private static AtomicLong idError = new AtomicLong();
private static ReadPrescriptionImpl readPrescription = new ReadPrescriptionImpl();
private static EscapePrescriptionImpl escapePrescription = new EscapePrescriptionImpl();
private static WritePrescriptionImpl writePrescription = new WritePrescriptionImpl();
public void start(String spBatchId, String spId, int threadNumber){
BatchPresEscapeServiceImpl.spBatchId = spBatchId;
BatchPresEscapeServiceImpl.spId = spId;
//加载缓存
CustomerCacheLoading.onLoadCoreDict(CacheTypeEnum.area.toString());
//读取待转义的处方
String strSql = "select distinct dt.PrescriptionUniqueId\n" +
"from prescription_base_batch as dt\n" +
"where dt.SPBatchID = '" + spBatchId + "'\n" +
"and dt.PrescriptionUniqueId not in(\n" +
"\tselect PrescriptionUniqueId\n" +
"\tfrom prescription_escaped\n" +
")\n" +
"order by dt.PrescriptionUniqueId;";
ids = new ConcurrentLinkedQueue<>();
LOGGER.info("正在获取需要转义的ID集合!");
try(Connection connection = DataSourceUtil.originalPrescription.getConnection()) {
ResultSet executeQuery = DbHelperBase.getInstance().executeQuery(connection, strSql);
while(executeQuery.next()){
ids.add(executeQuery.getInt(1));
}
} catch (SQLException e) {
LOGGER.error("获取需要转义的处方ID时发生异常!", e);
return;
}
//需要转义的处方数量
idsCount = ids.size();
LOGGER.info("成功获取需要转义的处方ID,处方数量:"+idsCount+"条!");
//************************重点在这里开始!!!********************************
// 创建一个可重用固定线程数的线程池
ExecutorService pool = Executors.newFixedThreadPool(threadNumber);
for(int i = 0 ; i < threadNumber ; i++){
Escape escape = new Escape();
pool.execute(escape);
}
//************************重点在这里结束!!!********************************
new Thread() {
@Override
public void run() {
try {
while (true) {
ThreadUtil.sleep(5, TimeUnit.SECONDS);
LOGGER.info(String.format("共需要处理:%s条,待处理:%s条!成功:%s条,错误:%s条!",
idsCount, ids.size(), idComplete.get(), idError.get()));
int activeCount = 0;
int waitCount = 0;
int stopCount = 0;
int otherCount = 0;
//获取活动的线程数,这里需要强制转换
activeCount = ((ThreadPoolExecutor)pool).getActiveCount();
otherCount = ((ThreadPoolExecutor)pool).getPoolSize()-activeCount;
LOGGER.info(String.format("线程状态(预计),活动:%s,等待:%s,结束:%s,其他:%s",
activeCount, waitCount, stopCount, otherCount));
}
} catch (Throwable th) {
LOGGER.error("获取处理进度时发生异常!", th);
}
}
}.start();
}
class Escape extends Thread{
@Override
public void run() {
Integer id = ids.poll();
escape(id);
while (id != null){
escape(ids.poll());
}
}
public void escape(int id){
try {
//读取处方
Collection<Prescription_base> prescriptionBases = readPrescription.readPrescription(spId,spBatchId,id);
DataEscapeExportModel dataEscapeExportModel = escapePrescription.receive(prescriptionBases);
writePrescription.receive(dataEscapeExportModel);
idComplete.getAndIncrement();
} catch (Exception e) {
idError.getAndIncrement();
LOGGER.error("转义时发生异常!处方ID:" + id, e);
}
}
}
}
调用:
package com.phhc.batchprocess;
import com.phhc.batchprocess.common.StaticVariables;
import com.phhc.batchprocess.escapeservice.impl.BatchPresEscapeServiceImpl;
import com.phhc.core.log.LoggerFactory;
import org.slf4j.Logger;
/**
* 转义服务测试
* Created by dongzy on 2018/1/16.
*/
public class EscapeServiceTest {
//日志
private static final Logger LOGGER = LoggerFactory.getLogger("batchprocess", EscapeServiceTest.class);
public static void main(String[] arg0) throws Exception {
BatchPresEscapeServiceImpl batchPresEscapeService = new BatchPresEscapeServiceImpl();
batchPresEscapeService.start(StaticVariables.spbatchId,StaticVariables.spId,15);
}
}
仅为思路!