`

Spring基于线程池的定时任务线挰异常实践

阅读更多

        结论:Spring基于线程池的定时任务,线挰异常或内存溢出导致线程挂了,还会新启线程继续工作。

实例重现:

springMVC.properties

#the thread pool config 
thread.corePoolSize=3
thread.maxPoolSize=8
thread.keepAliveSeconds=6
thread.queueCapacity=2

timing.query.status.interval=3000

springMVC-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
	xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:task="http://www.springframework.org/schema/task" 
	xsi:schemaLocation="http://www.springframework.org/schema/beans 
                    http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
                    http://www.springframework.org/schema/context
                    http://www.springframework.org/schema/context/spring-context-4.1.xsd
                    http://www.springframework.org/schema/mvc
                    http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd
                    http://www.springframework.org/schema/task  
       				http://www.springframework.org/schema/task/spring-task-4.1.xsd
                    ">
                    
	<context:component-scan base-package="com.bijian.study"></context:component-scan>   
    
	<!-- 系统配置文件 -->
	<context:property-placeholder location="classpath:springMVC.properties" />
    
    <mvc:annotation-driven></mvc:annotation-driven>
    
    <bean id="taskExecutor"
		class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
		<!-- 核心线程数,默认为1 -->
		<property name="corePoolSize" value="${thread.corePoolSize}" />
		<!-- 最大线程数,默认为Integer.MAX_VALUE -->
		<property name="maxPoolSize" value="${thread.maxPoolSize}" />
		<!-- 队列最大长度,一般需要设置值>=notifyScheduledMainExecutor.maxNum;默认为Integer.MAX_VALUE -->
		<property name="queueCapacity" value="${thread.queueCapacity}" />
		<!-- 线程池维护线程所允许的空闲时间,默认为60s -->
		<property name="keepAliveSeconds" value="${thread.keepAliveSeconds}" />
		<!-- 线程池对拒绝任务(无线程可用)的处理策略,目前只支持AbortPolicy、CallerRunsPolicy;默认为后者 -->
		<property name="rejectedExecutionHandler">
			<!-- AbortPolicy:直接抛出java.util.concurrent.RejectedExecutionException异常 -->
			<!-- CallerRunsPolicy:主线程直接执行该任务,执行完之后尝试添加下一个任务到线程池中,可以有效降低向线程池内添加任务的速度 -->
			<!-- DiscardOldestPolicy:抛弃旧的任务、暂不支持;会导致被丢弃的任务无法再次被执行 -->
			<!-- DiscardPolicy:抛弃当前任务、暂不支持;会导致被丢弃的任务无法再次被执行 -->
			<bean class="java.util.concurrent.ThreadPoolExecutor$CallerRunsPolicy" />
		</property>
	</bean>
	
	<task:scheduled-tasks> 
		<!--
		<task:scheduled ref="com.bijian.study.scheduled.TestScheduled" method="execute" cron="0 43 22 * * ?" />
		-->
		<task:scheduled ref="com.bijian.study.scheduled.TestScheduled" method="execute" fixed-delay="${timing.query.status.interval}" />
	</task:scheduled-tasks>
	
    <bean id="viewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">   
        <property name="viewClass"  
            value="org.springframework.web.servlet.view.JstlView" />   
        <property name="prefix" value="/WEB-INF/views" />
        <property name="suffix" value=".jsp" />   
    </bean>
</beans>

ScheduledService.java

package com.bijian.study.service;

public interface ScheduledService {

    void noNormalTest();
    
    void normalTest();
}

ScheduledServiceImpl.java

package com.bijian.study.service.impl;

import java.util.ArrayList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import com.bijian.study.entity.Person;
import com.bijian.study.service.ScheduledService;
import com.bijian.study.util.JsonUtil;

@Service("scheduledService")
public class ScheduledServiceImpl implements ScheduledService {

    private static Logger logger = LoggerFactory.getLogger(HelloServiceImpl.class);
    
    private static int COUNT = 0;
    
    @Override
    public void noNormalTest() {
        
        logger.info("entry ScheduledService noNormalTest:{}" ,"entry");
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
        try {
            int j = 200/0;
            List<Person> personList = new ArrayList<Person>(3);
            personList.add(new Person("bijian", 10));
            personList.add(new Person("lisi", 20));
            personList.add(new Person("zhangshan", 30));
            
            List<Person> personList2 = new ArrayList<Person>();
            int i = 0;
            int count = personList.size();
            while(i < count) {
                personList2.add(personList.get(i));
                if(i == 2) {
                    personList2.clear();
                }
            }
        }catch(Exception e) {
            logger.error("noNormalTest Exception:{}", e);
        }
        logger.info("entry ScheduledService noNormalTest:{}" ,"exit");
    }

    @Override
    public void normalTest() {
        
        logger.info("entry ScheduledService normalTest:{}" ,"entry");
//        try {
//            //Thread.sleep(10000);
//        } catch (InterruptedException e) {
//            // TODO Auto-generated catch block
//            e.printStackTrace();
//        }
        if(COUNT++ == 0) {
            List<Person> personList = new ArrayList<Person>();
            for(int i=0;i<1000000;i++) {
                personList.add(new Person("bijian", 10));
                personList.add(new Person("lisi", 20));
                personList.add(new Person("zhangshan", 30));
            }
            logger.info("personList:{}", JsonUtil.toFullJson(personList));
        }
    }
}

BaseScheduled.java

package com.bijian.study.scheduled;

public interface BaseScheduled {

    void execute();
}

TestScheduled.java

package com.bijian.study.scheduled;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import com.bijian.study.controller.HelloController;
import com.bijian.study.service.ScheduledService;

@Service(value = "com.bijian.study.scheduled.TestScheduled")
public class TestScheduled implements BaseScheduled {

    private static Logger logger = LoggerFactory.getLogger(HelloController.class);
    
    @Autowired
    @Qualifier("taskExecutor")
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;
    
    @Autowired
    private ScheduledService scheduledService;
    
    private static int COUNT = 0;
    
    @Override
    public void execute() {
        logger.info("enter TestScheduled");
        
        if(0 == COUNT) {
            threadPoolTaskExecutor.execute(new Runnable() {
                
                @Override
                public void run() {
                    try {
                        Thread.sleep(10000);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    scheduledService.noNormalTest();
                }
            });
        }else {
            
//            class MyThread implements Runnable {
//                
//                private String name;
//                
//                public MyThread(String name) {  
//                    this.name = name;  
//                }
//                
//                @Override
//                public void run() {
////                    try {
//                        logger.info("MyThread name:{}", name);
//                        try {
//                            Thread.sleep(30000);
//                        } catch (InterruptedException e) {
//                            // TODO Auto-generated catch block
//                            e.printStackTrace();
//                        }
//                        scheduledService.normalTest();
////                    }catch(Throwable e) {
////                        logger.info("exception:{}", e); 
////                    }
//                }
//            }

            threadPoolTaskExecutor.execute(new Runnable() {
                
                @Override
                public void run() {
                    scheduledService.normalTest();
                }
            });
        }
        COUNT ++;
        
        logger.info("exit TestScheduled");
    }
}

 

完整工程代码见附件《SpringMVC.zip》。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics