2009-07-22 28 views
72

Có cách nào tốt đẹp tiêu chuẩn để gọi phương thức chặn với thời gian chờ trong Java không? Tôi muốn có thể làm:Làm cách nào để gọi một số phương thức chặn với thời gian chờ trong Java?

// call something.blockingMethod(); 
// if it hasn't come back within 2 seconds, forget it 

nếu điều đó có ý nghĩa.

Cảm ơn.

+1

Là một tài liệu tham khảo, hãy kiểm tra Java Concurrency in Practice bởi Brian Goetz pp 126-134, đặc biệt là phần 6.3.7 "Đặt giới hạn thời gian vào công việc" –

Trả lời

123

Bạn có thể sử dụng một Executor:

ExecutorService executor = Executors.newCachedThreadPool(); 
Callable<Object> task = new Callable<Object>() { 
    public Object call() { 
     return something.blockingMethod(); 
    } 
}; 
Future<Object> future = executor.submit(task); 
try { 
    Object result = future.get(5, TimeUnit.SECONDS); 
} catch (TimeoutException ex) { 
    // handle the timeout 
} catch (InterruptedException e) { 
    // handle the interrupts 
} catch (ExecutionException e) { 
    // handle other exceptions 
} finally { 
    future.cancel(true); // may or may not desire this 
} 

Nếu future.get không trả lại trong vòng 5 giây, nó ném một TimeoutException. Thời gian chờ có thể được định cấu hình theo giây, phút, mili giây hoặc bất kỳ đơn vị nào có sẵn dưới dạng hằng số trong TimeUnit.

Xem JavaDoc để biết thêm chi tiết.

+5

Phương pháp chặn sẽ tiếp tục chạy ngay cả sau khi hết giờ, đúng không? –

+0

Điều đó tùy thuộc vào tương lai.cancel. Tùy thuộc vào phương thức chặn đang thực hiện tại thời điểm đó, nó có thể hoặc không thể chấm dứt. – skaffman

+0

được kiểm tra và làm việc tại đây. – Jus12

9

Bạn có thể kết thúc cuộc gọi theo số FutureTask và sử dụng phiên bản hết thời gian get().

Xem http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/FutureTask.html

+0

FutureTask isn'. t chính nó không đồng bộ, phải không? Ngày của riêng nó nó chỉ làm những điều đồng bộ, bạn cần phải kết hợp nó với một Executor để egt asynch hành vi. – skaffman

+0

Bạn cần một người thực thi như những gì bạn đã mã hóa –

1
Thread thread = new Thread(new Runnable() { 
    public void run() { 
     something.blockingMethod(); 
    } 
}); 
thread.start(); 
thread.join(2000); 
if (thread.isAlive()) { 
    thread.stop(); 
} 

Note, dừng mà bị phản đối, thay thế tốt hơn là để thiết lập một số cờ boolean không ổn định, bên blockingMethod() kiểm tra xem nó và thoát, như thế này:

import org.junit.*; 
import java.util.*; 
import junit.framework.TestCase; 

public class ThreadTest extends TestCase { 
    static class Something implements Runnable { 
     private volatile boolean stopRequested; 
     private final int steps; 
     private final long waitPerStep; 

     public Something(int steps, long waitPerStep) { 
      this.steps = steps; 
      this.waitPerStep = waitPerStep; 
     } 

     @Override 
     public void run() { 
      blockingMethod(); 
     } 

     public void blockingMethod() { 
      try { 
       for (int i = 0; i < steps && !stopRequested; i++) { 
        doALittleBit(); 
       } 
      } catch (InterruptedException e) { 
       throw new RuntimeException(e); 
      } 
     } 

     public void doALittleBit() throws InterruptedException { 
      Thread.sleep(waitPerStep); 
     } 

     public void setStopRequested(boolean stopRequested) { 
      this.stopRequested = stopRequested; 
     } 
    } 

    @Test 
    public void test() throws InterruptedException { 
     final Something somethingRunnable = new Something(5, 1000); 
     Thread thread = new Thread(somethingRunnable); 
     thread.start(); 
     thread.join(2000); 
     if (thread.isAlive()) { 
      somethingRunnable.setStopRequested(true); 
      thread.join(2000); 
      assertFalse(thread.isAlive()); 
     } else { 
      fail("Exptected to be alive (5 * 1000 > 2000)"); 
     } 
    } 
} 
1

Xem thêm ổi của TimeLimiter trong đó sử dụng một Công nhân hậu trường.

0

Giả blockingMethod chỉ ngủ đối với một số millis:

public void blockingMethod(Object input) { 
    try { 
     Thread.sleep(3000); 
    } catch (InterruptedException e) { 
     e.printStackTrace(); 
    } 
} 

Giải pháp của tôi là sử dụng wait()synchronized như thế này:

public void blockingMethod(final Object input, long millis) { 
    final Object lock = new Object(); 
    new Thread(new Runnable() { 

     @Override 
     public void run() { 
      blockingMethod(input); 
      synchronized (lock) { 
       lock.notify(); 
      } 
     } 
    }).start(); 
    synchronized (lock) { 
     try { 
      // Wait for specific millis and release the lock. 
      // If blockingMethod is done during waiting time, it will wake 
      // me up and give me the lock, and I will finish directly. 
      // Otherwise, when the waiting time is over and the 
      // blockingMethod is still 
      // running, I will reacquire the lock and finish. 
      lock.wait(millis); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
    } 
} 

Vì vậy, u có thể thay thế

something.blockingMethod(input)

đến

something.blockingMethod(input, 2000)

Hy vọng điều đó sẽ hữu ích.

3

Ngoài ra còn có giải pháp AspectJ cho thư viện đó với thư viện jcabi-aspects.

@Timeable(limit = 30, unit = TimeUnit.MINUTES) 
public Soup cookSoup() { 
    // Cook soup, but for no more than 30 minutes (throw and exception if it takes any longer 
} 

Nó không thể gọn gàng hơn, nhưng bạn phải phụ thuộc vào AspectJ và giới thiệu nó trong vòng đời xây dựng của bạn, tất nhiên.

Có một bài báo giải thích nó hơn nữa: Limit Java Method Execution Time

0

Bạn cần một việc thực hiện circuit breaker như chữ cái hiện hữu trong dự án failsafe trên GitHub.

1

Hãy thử điều này. Giải pháp đơn giản hơn. Đảm bảo rằng nếu khối không thực hiện trong thời hạn. quá trình sẽ chấm dứt và ném một ngoại lệ.

public class TimeoutBlock { 

private final long timeoutMilliSeconds; 
    private long timeoutInteval=100; 

    public TimeoutBlock(long timeoutMilliSeconds){ 
     this.timeoutMilliSeconds=timeoutMilliSeconds; 
    } 

    public void addBlock(Runnable runnable) throws Throwable{ 
     long collectIntervals=0; 
     Thread timeoutWorker=new Thread(runnable); 
     timeoutWorker.start(); 
     do{ 
      if(collectIntervals>=this.timeoutMilliSeconds){ 
       timeoutWorker.stop(); 
       throw new Exception("<<<<<<<<<<****>>>>>>>>>>> Timeout Block Execution Time Exceeded In "+timeoutMilliSeconds+" Milli Seconds. Thread Block Terminated."); 
      } 
      collectIntervals+=timeoutInteval;   
      Thread.sleep(timeoutInteval); 

     }while(timeoutWorker.isAlive()); 
     System.out.println("<<<<<<<<<<####>>>>>>>>>>> Timeout Block Executed Within "+collectIntervals+" Milli Seconds."); 
    } 

    /** 
    * @return the timeoutInteval 
    */ 
    public long getTimeoutInteval() { 
     return timeoutInteval; 
    } 

    /** 
    * @param timeoutInteval the timeoutInteval to set 
    */ 
    public void setTimeoutInteval(long timeoutInteval) { 
     this.timeoutInteval = timeoutInteval; 
    } 
} 

dụ:

try { 
     TimeoutBlock timeoutBlock = new TimeoutBlock(10 * 60 * 1000);//set timeout in milliseconds 
     Runnable block=new Runnable() { 

      @Override 
      public void run() { 
       //TO DO write block of code 
      } 
     }; 

     timeoutBlock.addBlock(block);// execute the runnable block 

    } catch (Throwable e) { 
     //catch the exception here . Which is block didn't execute within the time limit 
    } 
Các vấn đề liên quan