有时候代码需要连接数据库或者svn,连接时间并不长,但是前端调用接口超时的时间一般是一分钟,生产环境的情况下不会让用户等待一分钟,就需要后端控制接口超时时间,例子如下
原理
在Java中,超时返回的原理通常是通过使用多线程和并发编程实现的。具体来说,超时返回的实现方式可以是通过设置线程的超时时间,在超过该时间后中断线程的执行并返回一个超时异常。
以下是一个简单的示例代码,演示了如何在Java中实现超时返回:
public class TimeoutExample { public static void main(String[] args) { // 创建一个线程池,只包含一个线程 ExecutorService executor = Executors.newSingleThreadExecutor(); // 提交一个任务到线程池,并设置超时时间为3秒钟 Future<?> future = executor.submit(() -> { // 模拟一个耗时操作,持续5秒钟 try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("任务执行完成"); }); try { // 获取任务的结果,如果在3秒钟内任务没有执行完成,就会抛出一个TimeoutException异常 future.get(3, TimeUnit.SECONDS); } catch (TimeoutException e) { System.out.println("任务执行超时"); // 取消任务的执行 future.cancel(true); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } finally { // 关闭线程池 executor.shutdown(); } } }
在这个示例中,我们创建了一个单线程的线程池,并提交了一个任务到线程池中执行。我们还设置了超时时间为3秒钟,如果在3秒钟内任务没有执行完成,就会抛出一个TimeoutException异常。在catch块中,我们捕获了这个异常,并取消了任务的执行。最后,我们还关闭了线程池。
需要注意的是,在实际应用中,超时返回的实现方式可能会更加复杂和多样化,需要根据具体的业务场景和需求进行设计和实现。同时,还需要注意并发编程中可能存在的竞争条件和死锁等问题,以保证程序的正确性和可靠性。
方案
第一个例子
import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; /** * java实现超时返回 * 到了规定时间,不管有没有执行结果,我都要响应前端 * * @author xudong.shen * @date 2022/03/23 */ public class ThreadTest { public static void main(String[] args) { Callable<String> task = () -> { //设置执行响应时间的方法体 String str = ThreadTest.sleepJavaTest(); System.err.println("不论执行多久,我都在等着打印结果:"+str); return str; }; ExecutorService exeservices = Executors.newSingleThreadExecutor(); Future<String> future = exeservices.submit(task); try { //设置我最多等 5s,5s后无论如何我都要响应前端 String result = future.get(1, TimeUnit.SECONDS); System.err.println("我在规定时间内返回SUCCESS啦:"+result); } catch (Exception e) { e.printStackTrace(); //异常处理的方法 System.err.println("我在规定时间内没返回FAIL呢:这里是异常处理的方法"); } } public static String sleepJavaTest() { try { /*java中sleep与wait的区别 * 对于sleep方法导致程序暂停执行指定的时间,让出cpu给其他线程。但是它的监控状态依然保持,时间到了就会恢复。 * 在sleep方法中,线程不会释放对象锁。 * 对于wait方法,线程会放弃对象锁,进入等待次对象的等待锁定池, * 只有针对此对象调用notify()后,本线程才进入对象锁定池的准备。 * * 假设我执行了7s */ Thread.sleep(7000); return "当前函数成功的返回"; } catch (InterruptedException e) { e.printStackTrace(); return "执行异常"; } } }
第二个例子
方案:
在后端设置一个超时时间,当接口调用超过这个时间时,后端返回一个提示信息给前端。
具体实现步骤如下:
在后端代码中,使用try-catch语句块来包裹连接数据库或SVN的代码,以及调用接口的代码。
在try语句块中,设置一个超时时间(比如一分钟),使用线程来执行接口调用代码,并使用
Thread.sleep()方法让线程休眠一段时间,以模拟接口调用过程。
如果接口调用超过超时时间,在catch语句块中抛出一个异常或返回一个错误码,并将错误信息保存到日志文件中。
在catch语句块中,返回一个提示信息给前端,说明接口调用超时。
解释过程:
上述方案中,我们使用了一个try-catch语句块来控制接口调用过程。在try语句块中,我们模拟了接口调用过程,并使用Thread.sleep()方法让线程休眠一段时间。如果接口调用超过超时时间,catch语句块会捕获到这个异常并处理。在catch语句块中,我们可以抛出一个自定义的异常或返回一个错误码,并将错误信息保存到日志文件中,以便后续查看和分析。最后,我们将一个提示信息返回给前端,说明接口调用超时。通过这种方式,我们可以在后端控制接口的超时时间,避免用户等待过长时间。
import java.util.concurrent.*; public class TimeoutExample { public static void main(String[] args) { ExecutorService executor = Executors.newSingleThreadExecutor(); Future<String> future = executor.submit(() -> { // 在这里执行可能会超时的操作 String result = executeLongRunningOperation(); return result; }); try { // 设置超时时间为7秒 String result = future.get(7, TimeUnit.SECONDS); System.out.println("Result: " + result); } catch (TimeoutException e) { System.out.println("Operation timed out"); future.cancel(true); // 取消任务 } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } finally { executor.shutdown(); // 关闭线程池 } } private static String executeLongRunningOperation() { // 在这里执行你的数据库或SVN操作 return "Success"; } }
在上面的代码中,我们使用了一个单线程的线程池,并将可能会超时的操作提交给线程池执行。然后我们使用Future的get方法来获取操作的结果,并设置了7秒的超时时间。如果操作在规定的时间内没有完成,get方法会抛出一个TimeoutException异常。在异常处理代码中,我们取消了任务并关闭了线程池。
你可以将上述代码中的executeLongRunningOperation方法替换成你的数据库或SVN操作代码,并根据需要调整超时时间。这样,即使操作需要花费较长的时间,你的接口也不会因为超时而返回错误。
延伸
前端也是可以超时返回的
超时提醒前端的实现原理主要依赖于JavaScript的setTimeout()函数。
这个函数能在指定的时间后执行一个函数或指定的代码块。一般超时提醒的原理就是,在前端发起请求后,设置一个定时器,在定时器时间到达后还没有得到响应的话,那么就进行超时提醒。
以一个简单的fetch请求超时提醒为例,可以这样写:
let xhr = new XMLHttpRequest(); xhr.open('GET', '/api/some-data', true); xhr.onload = function(e) { if (xhr.status === 200) { // 请求成功,可以进行数据处理 let response = JSON.parse(xhr.responseText); console.log(response); } else { // 请求失败,进行错误处理 console.error('请求失败'); } }; xhr.onerror = function(e) { // 网络错误,如断网、服务器不可用等 console.error('网络错误'); }; // 设置请求超时时间(毫秒) xhr.timeout = 3000;
在这个例子中,如果服务器在3秒内没有响应,就会触发onerror回调,并显示网络错误信息。
需要注意的是,不同的浏览器对XMLHttpRequest的超时处理方式可能略有不同,有的浏览器可能没有提供timeout属性。因此在实际使用中,需要考虑到兼容性问题。同时,对于复杂的业务逻辑,可能需要结合Promise和async/await等ES6的特性来实现更复杂的超时处理方案。