手机端小强原创文章,java小强个人博客站点
当前位置: 首页 >> 理论 >> 用Java多线程,将任务分步骤处理

用Java多线程,将任务分步骤处理

54470 理论 | 2015-3-27

场景简单,其实就是在做WEB请求的时候,处理的结果需要同时通知到一个第三方服务器,通知后再把结果返回给客户端。

现在这个通知只是一个简单通知,如果直接加在客户端请求里面,客户端会在请求第三方服务器时堵塞。另外为了客户端不能超时,所以通知失败后也不敢多次请求。

 

这里可以使用定制任务来解决这个问题,一个客户端请求后产生一个定制的任务,然后服务后台进行多线程的异步处理,这样就会大大减少客户端的请求时间,同样最大程度保证这个通知是及时成功给第三方的。

定制任务我们需要一张表,来存储任务。同时需要多线程来执行这些任务。至于谁来开启这些任务,你可以使用定时器:http://javacui.com/framework/24.html,也可以使用后台线程。因为定时器已经有示例了,这里来说下后台线程。

 

因为是WEB服务,在服务启动的时候注册一个启动监听:

<!-- 初始化系统需要的配置项 开始 -->
<listener>
 <display-name>webListener</display-name>
 <listener-class>cn.com.vogue.listener.InitListener</listener-class>
</listener>
<!-- 初始化系统需要的配置项 结束 -->

然后我们来实现这个监听处理,主要任务就是开启一个后台线程,实时查询是否有需要执行的任务,有的话就分发任务给子线程。

同时为了系统的可配性,这个主线程是否开启做一个配置项,加载的时候判断一下即可:

isRunRulThread=0
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import cn.com.vogue.task.UrlTask;
import cn.com.vogue.utils.ResourceUrl;
import cn.com.vogue.utils.SpringFactory;
/**
 * 初始化
 */
public class InitListener implements ServletContextListener {
 private static Logger logger = LoggerFactory.getLogger(InitListener.class);
 public void contextDestroyed(ServletContextEvent sce) {
 }
 public void contextInitialized(ServletContextEvent sce) {
  if(ResourceUrl.isRunRulThread == 1){
   logger.warn("==========================>>>>>>>URL请求定制任务开启");
   UrlTask urlTaskBase = new UrlTask(); // 开始任务
   SpringFactory.executorService.execute(urlTaskBase);
  }
 }
}

这里我在SpringFactory里面定义了一个线程池,关于线程池:http://javacui.com/Theory/151.html

为了不对对方服务器造成压力,任务子线程最多开10个,加上主线程,一共11个,所以线程池不用太大。

public static ExecutorService executorService= Executors.newFixedThreadPool(11); 
// 定长线程池

主线程任务:查询是否有需要执行的任务,任务分发。

子线程:处理任务。

import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import cn.com.vogue.entity.UrlTaskBase;
import cn.com.vogue.service.systemManagement.UrlTaskBaseService;
import cn.com.vogue.utils.HttpUtils;
import cn.com.vogue.utils.SpringFactory;
public class UrlTask implements Runnable{
 private static Logger logger = LoggerFactory.getLogger(UrlTask.class);
 public static Integer isRun = new Integer(0); 
 // 该标量用于标记子线程在运行时,总线程不再派发新任务
 public void run() {
  while(true){
   try {
    UrlTaskBaseService taskSer = (UrlTaskBaseService)SpringFactory.getObject("urlTaskBaseService");
    List<UrlTaskBase> taskList = taskSer.findUrlTaskBaseUnSucc();
    if(null != taskList && taskList.size() > 0){
     logger.warn("本次需要执行的任务个数:" + taskList.size() + " 个");
     for(UrlTaskBase task : taskList){
      Init1ListenerRun run = new Init1ListenerRun(task, taskSer);
      SpringFactory.executorService.execute(run);
      try {Thread.sleep(1000);} catch (Exception e) {}
     }
    }else{
     logger.warn("没有找到要执行的任务,休眠后继续执行");
    }
   } catch (Exception e) {
    logger.error("查询执行任务时异常", e);
   }
   while(isRun > 0){
    try {Thread.sleep(1 * 1000);} catch (Exception e) {}
   }
   logger.error("60秒后进行下一次任务轮询");
   try {Thread.sleep(60 * 1000);} catch (Exception e) {} // 任务休眠60秒
  }
 }
}
class Init1ListenerRun implements Runnable {
 private static Logger logger = LoggerFactory.getLogger(Init1ListenerRun.class);
 public void run() {
  synchronized (UrlTask.isRun) { UrlTask.isRun ++; }
  try {
   logger.warn(task.getId() + " 任务路径:" + task.getTaskUrl());
   if(task.getTaskType() == 0){
    String result = HttpUtils.HttpGet(task.getTaskUrl());
    logger.warn(task.getId() + " 返回结果:" + result);
    if(null != result && !"".equals(result)){
     task.setBackStr(result);
    }
    task.setTryCount(task.getTryCount() + 1);
    taskSer.save(task);
   }else{
    String result = HttpUtils.HttpPost(task.getTaskUrl(), task.getTaskBody());
    logger.warn(task.getId() + " 返回结果:" + result);
    if(null != result && !"".equals(result)){
     task.setBackStr(result);
    }
    task.setTryCount(task.getTryCount() + 1);
    taskSer.save(task);
   }
  } catch (Exception e) {
   logger.error("执行任务异常", e);
  }
  synchronized (UrlTask.isRun) { UrlTask.isRun --; }
 }
 private UrlTaskBase task;
 private UrlTaskBaseService taskSer;
 public Init1ListenerRun(UrlTaskBase task, UrlTaskBaseService taskSer){
  this.task = task;
  this.taskSer = taskSer;
 }
}

这里用一个标量来标记有子线程在执行,主线程则休眠。

用对象来传递需要执行的任务,实体代码如下:

public class UrlTaskBase extends IdEntity{
 // 请求的地址,如果是Get,则带参数
 private String taskUrl;
 // 请求类型 0 GET 1 POST
 private int taskType;
 // POST 请求参数
 private String taskBody;
 // 成功的标记
 private String okMark;
 // 实际返回结果,和 okMark 一致为成功
 private String backStr;
 // 尝试次数
 private int tryCount;
 // 创建时间
 private String createTime;
}

任务分为GET请求和POST请求两种。

 

可以看到获取Spring对象用到了SpringFactory,关于这个对象http://javacui.com/framework/36.html

推荐您阅读更多有关于“ java 定时器 多线程 线程池 通知 ”的文章

上一篇:HttpClients下载与入门 下一篇:直接使用Spring JdbcTemplate执行查询

猜你喜欢

发表评论:

个人资料
blogger

java小强
没有思考,人生的路会越走越难!

搜索
分类
最新微语
  • 每个人的一生都是不同的,我们都需要负重前行。每一种生活都是不同的,我们都需要真实面对。所经历的,让我学会一件事,顺其自然。人,总有很多自己想要的,总有很多困难要面对,总有很多人要去爱,我们不断思考人生,却总是迷失自己。如今,我们最缺的不是金钱和时间,而是忘记了自己的初衷。

    2018-09-28 14:42

  • 车也学了,年也过了,生日也过了,村里的会也赶了,这次,是真的,年过去了。不过我没回京,也没有在家找工作,我在等什么吗?反正现在正合了我这个懒人的要求,不过,我歇不住,思考下人生。

    2018-03-20 00:11

  • 8月1日,我已离开奋斗多年的北京。不知道是暂时的离开,还是永久的离别,反正已经离职在家,告别每日上班,每天苦累的煎熬,过一段属于自己的生活。以前是专职工作,现在专职生活。

    2017-08-18 12:47

  • 又弄完一个项目,累成狗,但是感觉又进步不少,除了很多坑已经踩过,做起来也是轻车熟路。同时也认识到,程序不在于你多牛逼,而是在乎你的细节把控度,而细节的关注,是一个优秀程序员必须要注意的。另外,要相信自己,勇敢向前,没人生下来就是成功的,而且,成功的路,比成功本身更重要。

    2017-06-30 09:46

  • 今日北京再次沙尘暴来袭,吃了几年细粮,终于能来口粗粮了,不过大早上看见这场景,还是吓我一跳,不过随后就平静了,毕竟是老朋友了。进公司又发现一股烤糊的味道,真是祸不单行啊,例外都是污染。发了两个口罩,开启保护模式。

    2017-05-04 10:16

  • 更多»

最新文章
热门文章
随机文章