Spring调度程序和线程池执行程序

时间:2018-02-17 13:42:50

标签: java spring multithreading threadpoolexecutor spring-scheduled

我需要帮助设计基于多线程的应用程序,其中包括动态URL创建及其通过线程处理。

我在我的应用程序中使用spring scheduler,每30秒安排一次。从那个预定的方法我调用一些基于服务的apis,它在循环中,并且我需要每个API 1个线程池执行器,并且有1个线程处理。

由于此过程是从预定方法发生的,因此每次创建新线程池时,这都是问题所在。你可以在代码中看到。

我想要的是,如果对于任何API,如果线程池已经存在,那么该线程应该能够通过不创建新线程池并开始处理来自己识别。

如果需要更多信息,请告诉我。

欢迎并赞赏任何建议。谢谢

#API Properties
service.url=http://{0}.abc.net/xyz.php?
service.urls = abc1, abc2, abc3, abc4, abc5


@Service
public class APIServiceImpl implements APIService {

@Autowired
MsgService msgService;

private static final Logger LOGGER = Logger.getLogger(APIServiceImpl.class);
private static Properties fileProperties = PropertyUtility.getfileProperties();

@Scheduled(fixedDelayString = "30000")
public void getServiceMessage() throws ServiceException {
    try {
        long startTime = System.currentTimeMillis() / 1000L;
        long endTime = startTime + 30;
        String urlStr = fileProperties.getProperty("service.urls");
        String[] urls = urlStr.split(",");
        foreach(String url : urls){
            serviceApi(url.trim(), startTime, endTime);
        }
    } catch (Exception e) {
        throw new ServiceException(e);
    }
}

private void serviceApi(String url, long startTime, long endTime) {
    StringBuffer buffer = new StringBuffer();
    buffer.append(java.text.MessageFormat.format(fileProperties.getProperty("service.url"), url));
    buffer.append("starttime=" + startTime);
    buffer.append("&endtime=" + endTime);
    ExecutorService executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS,
        new ArrayBlockingQueue<Runnable>(100), new ThreadPoolExecutor.CallerRunsPolicy());
    executor.submit(new APIThreadHandler(buffer.toString(), messageService));
}  


public class APIThreadHandler implements Runnable {

private static final Logger LOGGER = Logger.getLogger(APIThreadHandler.class);
private String url;
MsgService msgService;

public APIThreadHandler(String url, MsgService msgService) {
    this.url = url;
    this.msgService = msgService;
}

public void run() {
    System.out.println("ThreadID: " + Thread.currentThread().getId());
    try {
        URL srcUrl = new URL(url);
        List<Map<?, ?>> data = readObjectsFromCsv(srcUrl);
        JSONArray jsonArray = new JSONArray(data);
        for (int i = 0; i < jsonArray.length(); i++) {
            msgService.sendMessage(jsonArray.getJSONObject(i));
        }
    } catch (Exception e) {
        LOGGER.error("Exception occured - ", e);
    }
}

private static List<Map<?, ?>> readObjectsFromCsv(URL url) {
    List<Map<?, ?>> listMap = null;
    try {
        CsvSchema bootstrap = CsvSchema.emptySchema().withHeader();
        CsvMapper csvMapper = new CsvMapper();
        MappingIterator<Map<?, ?>> mappingIterator = csvMapper.readerFor(Map.class).with(bootstrap).readValues(url);
        listMap = mappingIterator.readAll();
    } catch (Exception e) {
        LOGGER.error("Exception occured - ", e);
    }
    return listMap;
}

1 个答案:

答案 0 :(得分:0)

您可以使用@ PostConstruct 初始化线程池一次,并且每次都重复使用它。只有在加载应用程序上下文时才会调用此项。

@PostConstruct
public void init() {
 executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS,
    new ArrayBlockingQueue<Runnable>(100), new ThreadPoolExecutor.CallerRunsPolicy());
}