线程池和线程的应用

在一些对写有严格要求的业务中,每一次update都是一次特别谨慎的操作,比如在一次时间较长的数据计算中,发起一项计算后,就不需要重复的发起这项计算,一是节省资源,而是防止数据重复出现导致数据错误;

这时我们就会想到一个名词,线程,由于刚接触不久,这里就做一下简单的讲解,如有错误,欢迎指正。

在实战项目中线程池的应用分三个步骤:

  1、创建单线程池类:

首先创建基线程:

public abstract class BaseComputeThread implements Runnable{/**
     * 任务名称
     */
    protected String taskName="";
    public String getTaskName() {
        return taskName;
    }
    /**
     * 任务描述
     */
    protected String taskDescription="";
    
    
    @Override
    public void run() {
        //判断依赖任务是否完成
        checkDependTasks();
        //任务执行
        try {//开始任务
            doJob();
        } catch (Exception e) {
            System.out.println("异常了");
        }
    }
    
    /**
     * 任务
     * 此方法为虚方法,实际调用子类的实现
     */
    protected abstract void doJob();
}

所有的线程继承基类:

@Component
public class TestThread extends BaseComputeThread {
    
    @Autowired
    private TestService testService;

    /**
     * 构造函数
     */
    public TestThread() {
        super.taskName = "TestThread";
        super.taskDescription = "我要控制的方法名称";
    }

    /**
     * 线程执行入口方法
     * 
     * @Exception 捕获异常
     */
    @Override
    public void run() {
        super.run();
    }

    @Override
    protected void doJob() {
        testService.test();
    }

}

2、创建线程, 使用单线程池,防止同一类型的计算任务同时执行多次,并引入测试线程:

private ExecutorService testThreadpool = Executors.newSingleThreadExecutor();
@Autowired
private TestThread testThread;

3、执行线程:

testThreadpool.execute(tsetThread);

拓展:

有的业务需求中不仅仅要求任务单线程执行,还需要某个方法在执行中,不让该方法再次执行,或者不让改方法一段时间内再次执行:

1、这时我们需要一个控制再次执行的类

public class ComputeTaskController {
    private final String SUCCESS ="提交后台执行任务成功!";
    private final String RUNNING ="正在执行任务中,请稍后再试!";
    
    /**
     * 用来存储计算任务的状态的HashMap
     * key为任务名称,value为状态+“;”+时间戳的字符串
     */
    private static HashMap<String, String> taskStateMap = new HashMap<String, String>();
    
    /**
     * 判断任务是否需要执行
     * 如果短时间内执行过可以不再执行
     * @param taskName 任务名称
     * @return 
     * @throws Exception
     */
    public static boolean checkTaskState(String taskName){
        boolean ret = false;
        String taskState = taskStateMap.get(taskName);
        if(taskState==null){
            //还没有执行过
            ret = true;
        }else{
            String[] tempsStrings = taskState.split(";");
            if(tempsStrings[0].equals("0")){
                //正在执行
                ret = false;
            }else if(tempsStrings[0].equals("1")){
                //任务完成
                long lasttime = Long.parseLong(tempsStrings[1]);
                long curtime = new Date().getTime();
                if(curtime-lasttime>1000 * 60 * 60){
                    //一小时内执行过就不再执行
                    //return false;
                }
                return true;
            }else if(tempsStrings[0].equals("2")){
                //任务异常终止
                ret = true;
            }
        }
        return ret;
    }
    
    /**
     * 设置任务运行状态
     * @param taskName 任务名称
     * @param state 任务状态   0任务开始;1任务完成;2任务异常终止
     * @return 
     * @throws Exception
     */
    public static synchronized void setTaskState(String taskName, String state) {
        String curTimeString = String.valueOf(new Date().getTime());
        taskStateMap.put(taskName, state+";"+curTimeString);
    }
}

2、在需要执行任务时,修改上面第三步调用任务的方法:

public String runTestTask(HttpServletRequest request) {
        if (!ComputeTaskController.checkTaskState("TestThread")) {
            return "任务正在执行";
        } else {
            testThreadpool.execute(testThread);
        }
        return "任务提交执行成功";
; }
原文地址:https://www.cnblogs.com/bestxyl/p/8399830.html