如何在 Java 中实现同步方法超时?

     2023-02-19     290

关键词:

【中文标题】如何在 Java 中实现同步方法超时?【英文标题】:How to implement synchronous method timeouts in Java? 【发布时间】:2013-06-18 10:55:02 【问题描述】:

我有一个同步执行路径,它需要在给定的时间范围内完成或超时。假设我有一个带有 main() 方法的类,在该类中我调用方法 A(),该方法又调用 B(),而该方法又调用相同或不同类的 C() .....所有同步而不使用外部资源,如数据库、Web 服务或文件系统(其中每个都可以使用 TxManager 或相应的超时 API 独立超时)。所以它更像是 CPU 或内存密集型计算。如何在 Java 中为其超时编写代码?

我查看了 TimerTask,但更多的是使流异步和调度任务。还有其他建议吗?

【问题讨论】:

ExecutorServiceCallables 可能是!!! 这是一个迭代任务吗?如果您的超时已到,您能否检查每次迭代? 我更多的是寻找一个通用的解决方案,而不是让它具体实现......因为可能有一个计算可能需要足够长的时间才能完成。 【参考方案1】:

您可以运行一个并行线程,该线程将等待指定的超时并中断当前线程,然后运行A()。但是a、b、c必须是可中断的,即定期检查当前线程的中断标志并抛出InterruptedException,否则将不起作用

    final Thread current = Thread.currentThread();
    Thread timer = new Thread() 
        public void run() 
            try 
                Thread.sleep(5000);
                current.interrupt();
             catch (InterruptedException e) 
                // timer stopped
            
        ;
    ;
    try 
        A();  // this throws InterruptedException if interrupted by timer
        timer.interrupt(); // no timeout lets stop the timer
     catch (InterruptedException e) 
        // timeout
    

【讨论】:

【参考方案2】:

您应该使用ExecutorService 来做到这一点

ExecutorService executor = Executors.newSingleThreadExecutor();
Future<String> future = executor.submit(new Callable() 

    public String call() throws Exception 
        //do operations you want
        return "OK";
    
);
try 
    System.out.println(future.get(2, TimeUnit.SECONDS)); //timeout is in 2 seconds
 catch (TimeoutException e) 
    System.err.println("Timeout");

executor.shutdownNow();

【讨论】:

这实际上会停止 Callable 还是只是让 get() 超时? 只是get的“超时”,你需要通过“cancel(true)”方法或者调用executor.shutdownNow()来中断future【参考方案3】:

另见post 该方法是让您的应用程序在其逻辑中处理超时。为此,您可以定义一些计时器类和特殊检查方法,例如:

  public class TimeoutApp 
    MyTimer timer;
    Thread timerThread;

    public static void main(String... args) 
        new TimeoutApp().execute();
    

    private void execute() 
        try 
            startTimer(1000);
            action1();
            checkTimeout();
            action2();
            checkTimeout();
            action3();
            stopTimer();

         catch (MyTimeoutException e) 
            System.out.println("Interrupted on timeout!");
            // ...clearing code if needed
            System.exit(1);
         catch (InterruptedException e) 
            System.out.println("Interrupted by exception!");
            // ...clearing code if needed
            e.printStackTrace();
            System.exit(1);
        
    

    private void action1() throws InterruptedException 
        Thread.sleep(600);
        System.out.println("action 1");
    

    private void action2() throws InterruptedException 
        Thread.sleep(500);
        System.out.println("action 2");
    

    private void action3() 
        System.out.println("action 3");
    

    private void checkTimeout() throws MyTimeoutException 
        if (timer.isTimeoutReached()) 
            throw new MyTimeoutException();
        
    

    private void startTimer(long timeout) 
        timer = new MyTimer(timeout);
        timerThread = new Thread(timer);
        timerThread.start();
    

    private void stopTimer() 
        timerThread.interrupt();
    

    private class MyTimer implements Runnable 
        private long timeout;
        private boolean timeoutReached = false;

        public MyTimer(long timeout) 
            this.timeout = timeout;
        

        public void run() 
            long time = System.currentTimeMillis();
            while (!timeoutReached && !Thread.interrupted()) 
                if ((System.currentTimeMillis() - time) > timeout) 
                    timeoutReached = true;
                
            
        

        public boolean isTimeoutReached() 
            return timeoutReached;
        
    

    private class MyTimeoutException extends Exception 
    

【讨论】:

非常低效。如果您的 action2() 是一个长时间运行的操作并且在其执行之间发生超时怎么办?【参考方案4】:

您无法使用超时进行同步调用,但您可以使用第二个线程来模拟它。这是一个例子:

package com.ardevco.example;

import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;


class ExceptionThrower 
   public static <R> R throwUnchecked(Throwable t) 
      return ExceptionThrower.<RuntimeException, R> trhow0(t);
   

   @SuppressWarnings("unchecked")
   private static <E extends Throwable, R> R trhow0(Throwable t) throws E 
      throw (E) t;
   


class TestApplicationException1 extends Exception 
   private static final long serialVersionUID = 1L;

   public TestApplicationException1(String string) 
      super(string);
   
;

class TestApplicationException2 extends Exception 
   private static final long serialVersionUID = 1L;

   public TestApplicationException2(String string) 
      super(string);
   
;

class TestApplicationTimeoutException extends Exception 
   private static final long serialVersionUID = 1L;

   public TestApplicationTimeoutException(String string) 
      super(string);
   ;


public class SynchronousTimeoutTester 

   public static final long SYNC_METHOD_TIMEOUT_IN_MILLISECONDS = 2000L;
   private final ExecutorService executorService = Executors.newSingleThreadExecutor();

   public static void main(String[] args) 
      SynchronousTimeoutTester tester = new SynchronousTimeoutTester();
      /* call the method asynchronously 10 times */
      for (int i = 0; i < 10; i++) 
         try 
            System.out.println("Result sync call: " + tester.getAsynchTest());
         
         catch (TestApplicationException1 e) 
            System.out.println("catched as TestApplicationException1: " + e);
         
         catch (TestApplicationException2 e) 
            System.out.println("catched as TestApplicationException2: " + e);
         
         catch (TestApplicationTimeoutException e) 
            System.out.println("catched as TestApplicationTimeoutException: " + e);
         
         catch (InterruptedException e) 
            System.out.println("catched as InterruptedException: " + e);
         
         catch (Exception e) 
            System.out.println("catched as Exception: " + e);
         
      

      tester.shutdown();
   

   private void shutdown() 
      executorService.shutdown();
      try 
         executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
      
      catch (InterruptedException e) 
         System.out.println("Error stopping threadpool:" + e);
      
   

   private Integer testAsynch() throws TestApplicationException1, TestApplicationException2, InterruptedException 
      Random random = new Random();
      switch (random.nextInt(10)) 
         case 0:
            return 0;
         case 1:
            throw new TestApplicationException1("thrown TestApplicationException1");
         case 2:
            throw new TestApplicationException2("thrown TestApplicationException2");
         case 3:
            Thread.sleep(10000L);
            return -1;
         case 4:
            throw new RuntimeException("thrown Exception");
         default:
            return random.nextInt(10);
      
   

   private Integer getAsynchTest() throws TestApplicationException1, TestApplicationException2, Exception 
      Integer dummy = null;

      Future<Integer> testAsynchF = executorService.submit(
                                                           new Callable<Integer>() 
                                                              public Integer call() throws Exception 
                                                                 return testAsynch();
                                                              
                                                           );

      try 
         dummy = testAsynchF.get(SynchronousTimeoutTester.SYNC_METHOD_TIMEOUT_IN_MILLISECONDS, TimeUnit.MILLISECONDS);
      
      catch (ExecutionException e1) 
         System.out.println("in getAsynchTest: ExecutionException: " + e1);
         ExceptionThrower.throwUnchecked(e1.getCause());
      
      catch (TimeoutException e1) 
         System.out.println("in getAsynchTest: TimeoutException: " + e1);
         throw new TestApplicationTimeoutException("TimeoutException" + e1);
      
      catch (InterruptedException e1) 
         System.out.println("in getAsynchTest: InterruptedException: " + e1);
         throw new Exception(e1);
      

      return dummy;
   


【讨论】:

如何在 C++ 中实现函数超时

】如何在C++中实现函数超时【英文标题】:Howtoimplementtimeoutforfunctioninc++【发布时间】:2017-03-2520:18:51【问题描述】:我有函数f;我想在启动f后抛出异常1s。我无法修改f()。用c++可以吗?tryf();catch(TimeoutException&e)//timeout【问题讨... 查看详情

如何在阻塞模式 NIO 中实现超时?

】如何在阻塞模式NIO中实现超时?【英文标题】:HowdoesoneimplementatimeoutinblockingmodeNIO?【发布时间】:2013-02-1317:58:10【问题描述】:我没有使用任何选择器或类似的东西。我只有一个简单的ServerSocketChannel监听和一个SocketChannel以阻... 查看详情

如何在android中实现请求超时?

】如何在android中实现请求超时?【英文标题】:howtoimplementrequesttimeoutinandroid?【发布时间】:2011-03-1320:54:07【问题描述】:朋友们,当我尝试调用web服务并且服务器/互联网不可用时,我遇到了问题。看来,连接需要很长时间才... 查看详情

如何在 Grails 中实现超时页面

】如何在Grails中实现超时页面【英文标题】:HowtoimplementatimeoutpageinGrails【发布时间】:2011-10-2600:59:52【问题描述】:我需要一些帮助来处理Grails应用程序中的超时问题。上下文:在我的Grails应用程序中,我显示了敏感信息。显... 查看详情

java示例代码_在java中实现超时,以查看响应是否出现

java示例代码_在java中实现超时,以查看响应是否出现 查看详情

如何在 grails 中实现请求超时?

】如何在grails中实现请求超时?【英文标题】:HowdoIimplementarequesttimeoutingrails?【发布时间】:2011-04-1123:02:22【问题描述】:我希望能够在grails中设置可配置的(通过控制器/操作)请求超时。目标是以确定性的方式处理罕见的高... 查看详情

java示例代码_在RCP应用程序/SWT中实现超时

java示例代码_在RCP应用程序/SWT中实现超时 查看详情

java示例代码_我应该如何在Java中实现字符串到方法的映射

java示例代码_我应该如何在Java中实现字符串到方法的映射 查看详情

node.js中实现同步操作的3种实现方法

...3种实现方法,本文用实例讲解一些需要同步操作的情况下,如何编程实现,需要的朋友可以参考下众所周知,异步是得天独厚的特点和优势,但同时在程序中同步的需求(比如控制程序的执行顺序为:func1->func2->func3)也是很常... 查看详情

如何在 Java 中实现包装装饰器?

】如何在Java中实现包装装饰器?【英文标题】:HowtoimplementawrapperdecoratorinJava?【发布时间】:2016-04-0807:20:35【问题描述】:问题是创建现有对象的动态增强版本。我无法修改对象的Class。相反,我必须:子类化它将现有对象包装... 查看详情

在同步对象中实现异步接口

】在同步对象中实现异步接口【英文标题】:ImplementingAsynchronousInterfacesinSynchronousobjects【发布时间】:2018-11-0410:10:05【问题描述】:在学习异步编程时,我一直在尝试实现一个既适用于异步类又适用于同步类的接口,但我看到了... 查看详情

如何在 C++ 中实现方法返回类似 Java 中的对象 [关闭]

】如何在C++中实现方法返回类似Java中的对象[关闭]【英文标题】:HowtoimplementamethodreturnsomethinglikeObject-in-JavainC++[closed]【发布时间】:2012-10-2902:36:32【问题描述】:我正在从Java背景学习C++,这是我刚刚遇到的一个问题:假设我有... 查看详情

如何在ios中实现刷新令牌

】如何在ios中实现刷新令牌【英文标题】:Howtoimplementrefreshtokeninios【发布时间】:2018-04-0610:29:31【问题描述】:只有一些api调用需要令牌。当401发生时,将进行刷新令牌调用。对于每次调用,令牌都会刷新。401发生时如何同步... 查看详情

如何在java中实现接口类

】如何在java中实现接口类【英文标题】:Howtogetimplementinginterfaceclassinjava【发布时间】:2017-05-1514:13:34【问题描述】:我的问题非常接近Java通知/观察者设计模式。我从事不同的java/Android编程。我想了解的一件事是发布者如何知... 查看详情

java中实现线程通信的三个方法的作用是什么?

Java提供了3个方法解决线程之间的通信问题,均是java.lang.Object类的方法,都只能在同步方法或者同步代码块中使用,否则会抛出异常。方法名作用finalvoidwait()表示线程一直等待,直到其它线程通知voidwait(longtimeout)线程等待指定毫... 查看详情

在 Java 中实现单例模式的有效方法是啥? [关闭]

】在Java中实现单例模式的有效方法是啥?[关闭]【英文标题】:WhatisanefficientwaytoimplementasingletonpatterninJava?[closed]在Java中实现单例模式的有效方法是什么?[关闭]【发布时间】:2010-09-0909:35:22【问题描述】:在Java中实现单例设计... 查看详情

node.js中实现同步操作的3种实现方法

众所周知,异步是得天独厚的特点和优势,但同时在程序中同步的需求(比如控制程序的执行顺序为:func1->func2->func3)也是很常见的。本文就是对这个问题记录自己的一些想法。需要执行的函数: varfunc1=function(req,res,cal... 查看详情

如何java中实现上传头像功能?

参考技术A方法一:①下载fileupload插件,将文件转换成流;②再写出到指定的路径,将存储路径存储在数据库中。方法二:可以将头像文件做一次压缩处理,原图一个路径,压缩图一个路径。压缩图路径展示的是小图,原图路径... 查看详情