Executors多线程编程实例之newFixedThreadPool

基础储备:
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);
    }
}

仅为思路!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值