leifengpeng
fplei
采纳率33.3%
2020-01-09 13:43 阅读 563
已采纳

Springmvc在线程池中无法使用Service

问题:我在项目中使用线程池新建了线程列队,controller请求后把耗时任务交给列队处理,
列队中需要service注入,但是在Test中测,子线程无法使用service的方法,代码如下:
TaskQueueHandler.java

public interface TaskQueueHandler {
    String getTaskName();
    int doInvoke();
}

TaskSerialQueueService.java
...

@PostConstruct
    public void init(){
        serviceThreadStatus=service.submit(new Thread(new Runnable() {
            @Override
            public void run() {
                while (running){
                    try{
                        TaskQueueHandler taskQueueHandler= tasks.take();
                        if(taskQueueHandler!=null){
                            try{
                                taskQueueHandler.doInvoke();
                            }catch (Exception e){
                                log.error(taskQueueHandler.getTaskName()+" doInvoke Error!",e.getCause());
                            }
                        }
                    }catch (InterruptedException e){
                        running=false;
                    }
                }
            }
        }));
    }
        /**
     * 往列队中添加新任务
     * @param taskQueueHandler
     * @return
     */
    public synchronized boolean addTask(TaskQueueHandler taskQueueHandler){
        if(!checkServiceIsActive()){
            activeService();
        }
        boolean success= tasks.offer(taskQueueHandler);
        if(!success){
            log.warn(taskQueueHandler.getTaskName()+"任务列队添加失败!");
        }
        return success;
    }
    ...

    WxPayNotifyTask.java
public class WxPayNotifyTask implements TaskQueueHandler{
    private String orderNo;
    public WxPayNotifyTask(String mOrderNo){
        this.orderNo=mOrderNo;
    }
    @Override
    public String getTaskName() {
        return WxPayNotifyTask.class.getSimpleName();
    }
    private OrderService orderService;

    @Override
    public int doInvoke() {
        System.out.println("orderNo="+orderNo);
        orderService= (OrderService)SpringUtils.getBean("orderService");
        try{
            OrderBean orderBean=orderService.queryByOrderNo(orderNo);
            System.out.println(orderBean.toString());
        }catch (Exception e){
            e.printStackTrace();
        }
        return 0;
    }
}

测试代码中调用

@Autowired
private TaskSerialQueueService taskQueueService;
taskQueueService.addTask(new WxPayNotifyTask("379991638464417792"));

测试发现报错信息如下

org.springframework.transaction.CannotCreateTransactionException: Could not open JDBC Connection for transaction; nested exception is java.sql.SQLException: interrupt
    at org.springframework.jdbc.datasource.DataSourceTransactionManager.doBegin(DataSourceTransactionManager.java:289)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:377)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:461)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:277)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:673)
    at com.superior.chalk.service.order.OrderServiceImpl$$EnhancerBySpringCGLIB$$d45a5b10.queryByOrderNo(<generated>)
    at com.superior.chalk.task.WxPayNotifyTask.doInvoke(WxPayNotifyTask.java:27)
    at com.superior.chalk.task.queue.TaskSerialQueueService$1.run(TaskSerialQueueService.java:35)
    at java.lang.Thread.run(Thread.java:745)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)
Caused by: java.sql.SQLException: interrupt

最后发现如直接在test中使用
new WxPayNotifyTask("379991638464417792").invoke()是可以使用service的,但是在子线程中能获取到service但调用service的方法就报错。

先谢谢各位大佬帮忙分析分析!

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享

1条回答 默认 最新

  • 已采纳
    qq_23292875 Hefei19881002 2020-01-09 14:02
    一般service中会开启事务的,你这么多线程公用一个service对象当然会出问题,建议每条线程都用自己创建的service对象
    
    点赞 评论 复制链接分享

相关推荐