มีวิธีที่ดีมาตรฐานในการเรียกใช้วิธีการบล็อกด้วยการหมดเวลาใน Java หรือไม่? ฉันต้องการที่จะทำได้:
// call something.blockingMethod();
// if it hasn't come back within 2 seconds, forget it
ถ้ามันสมเหตุสมผล
ขอบคุณ.
มีวิธีที่ดีมาตรฐานในการเรียกใช้วิธีการบล็อกด้วยการหมดเวลาใน Java หรือไม่? ฉันต้องการที่จะทำได้:
// call something.blockingMethod();
// if it hasn't come back within 2 seconds, forget it
ถ้ามันสมเหตุสมผล
ขอบคุณ.
คำตอบ:
คุณสามารถใช้ 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
}
หากfuture.get
ไม่กลับมาใน 5 วินาทีมันจะพ่นไฟล์TimeoutException
. การหมดเวลาสามารถกำหนดเป็นวินาทีนาทีมิลลิวินาทีหรือหน่วยใด ๆ ที่มีให้เป็นค่าคงที่ในTimeUnit
.
ดูJavaDocสำหรับรายละเอียดเพิ่มเติม
BlockingMethodCallable
ซึ่งมี contructor ยอมรับพารามิเตอร์ที่คุณต้องการส่งผ่านblockingMethod()
และเก็บไว้เป็นตัวแปรสมาชิก (อาจเป็นขั้นสุดท้าย) จากนั้นภายในcall()
ส่งพารามิเตอร์เหล่านั้นไปยังไฟล์blockMethod()
.
future.cancel(true)
- วิธีการยกเลิก (บูลีน) ในประเภทอนาคต <Object> ใช้ไม่ได้กับอาร์กิวเมนต์ ()
คุณสามารถตัดสายใน a FutureTask
และใช้ get () เวอร์ชันหมดเวลา
ดูhttp://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/FutureTask.html
ดูTimeLimiterของ Guava ซึ่งใช้ Executor อยู่เบื้องหลัง
เป็นเรื่องดีมากที่ผู้คนพยายามนำสิ่งนี้ไปใช้ในหลาย ๆ ด้าน แต่ความจริงก็คือไม่มีทาง
นักพัฒนาส่วนใหญ่จะพยายามวางสายการบล็อกไว้ในชุดข้อความอื่นและมีอนาคตหรือตัวจับเวลา แต่ไม่มีวิธีใดใน Java ที่จะหยุดเธรดภายนอกได้นับประสากรณีเฉพาะบางกรณีเช่นเมธอด Thread.sleep () และ Lock.lockInterruptably () ที่จัดการเธรดการขัดจังหวะอย่างชัดเจน
ดังนั้นคุณมีเพียง 3 ตัวเลือกทั่วไป:
วางสายการบล็อคของคุณไว้ในเธรดใหม่และหากหมดเวลาคุณเพียงแค่ดำเนินการต่อปล่อยให้เธรดนั้นแขวนไว้ ในกรณีนี้คุณควรตรวจสอบให้แน่ใจว่าเธรดถูกตั้งค่าเป็นเธรด Daemon วิธีนี้เธรดจะไม่หยุดแอปพลิเคชันของคุณจากการยุติ
ใช้ Java API ที่ไม่ปิดกั้น ดังนั้นสำหรับเครือข่ายเช่นใช้ NIO2 และใช้วิธีการไม่บล็อก สำหรับการอ่านจากคอนโซลให้ใช้ Scanner.hasNext () ก่อนบล็อกเป็นต้น
หากการโทรที่บล็อกของคุณไม่ใช่ IO แต่เป็นตรรกะของคุณคุณสามารถตรวจสอบซ้ำ ๆThread.isInterrupted()
เพื่อตรวจสอบว่าถูกขัดจังหวะภายนอกหรือไม่และมีการโทรอีกครั้งในเธรดthread.interrupt()
การบล็อก
หลักสูตรเกี่ยวกับภาวะพร้อมกันนี้https://www.udemy.com/java-multithreading-concurrency-performance-optimization/?couponCode=CONCURRENCY
เรียนรู้พื้นฐานเหล่านั้นอย่างแท้จริงหากคุณต้องการเข้าใจวิธีการทำงานใน Java จริงๆแล้วมันพูดถึงข้อ จำกัด และสถานการณ์เฉพาะเหล่านั้นและวิธีดำเนินการเกี่ยวกับข้อ จำกัด เหล่านั้นในการบรรยาย
ฉันเองพยายามตั้งโปรแกรมโดยไม่ใช้การปิดกั้นการโทรให้มากที่สุด มีชุดเครื่องมือเช่น Vert.x ที่ทำให้การทำ IO เป็นเรื่องง่ายและมีประสิทธิภาพและไม่มีการดำเนินการ IO แบบอะซิงโครนัสและไม่ปิดกั้น
ฉันหวังว่ามันจะช่วยได้
นอกจากนี้ยังมีโซลูชัน AspectJ สำหรับสิ่งนั้นด้วยห้องสมุดด้าน jcabi
@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
}
มันไม่สามารถรวบรัดได้มากกว่านี้ แต่คุณต้องขึ้นอยู่กับ AspectJ และแนะนำมันในวงจรการสร้างของคุณแน่นอน
มีบทความอธิบายเพิ่มเติม: จำกัด เวลาดำเนินการเมธอด Java
Thread thread = new Thread(new Runnable() {
public void run() {
something.blockingMethod();
}
});
thread.start();
thread.join(2000);
if (thread.isAlive()) {
thread.stop();
}
โปรดทราบว่าการหยุดนั้นเลิกใช้แล้วทางเลือกที่ดีกว่าคือการตั้งค่าสถานะบูลีนที่ระเหยได้ภายในการปิดกั้นวิธีการ () ตรวจสอบและออกดังนี้:
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)");
}
}
}
ลองทำตามนี้ วิธีง่ายๆมากขึ้น รับประกันว่าหากบล็อกไม่ดำเนินการภายในเวลาที่กำหนด กระบวนการนี้จะยุติและแสดงข้อยกเว้น
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;
}
}
ตัวอย่าง:
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
}
ฉันให้รหัสที่สมบูรณ์แก่คุณที่นี่ แทนวิธีที่ฉันเรียกคุณสามารถใช้วิธีของคุณ:
public class NewTimeout {
public String simpleMethod() {
return "simple method";
}
public static void main(String[] args) {
ExecutorService executor = Executors.newSingleThreadScheduledExecutor();
Callable<Object> task = new Callable<Object>() {
public Object call() throws InterruptedException {
Thread.sleep(1100);
return new NewTimeout().simpleMethod();
}
};
Future<Object> future = executor.submit(task);
try {
Object result = future.get(1, TimeUnit.SECONDS);
System.out.println(result);
} catch (TimeoutException ex) {
System.out.println("Timeout............Timeout...........");
} catch (InterruptedException e) {
// handle the interrupts
} catch (ExecutionException e) {
// handle other exceptions
} finally {
executor.shutdown(); // may or may not desire this
}
}
}
สมมติว่าblockingMethod
แค่นอนเป็นเวลามิลลิวินาที:
public void blockingMethod(Object input) {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
วิธีแก้ปัญหาของฉันคือการใช้wait()
และsynchronized
เช่นนี้:
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();
}
}
}
ดังนั้นคุณสามารถแทนที่
something.blockingMethod(input)
ถึง
something.blockingMethod(input, 2000)
หวังว่าจะช่วยได้