Java'da zaman aşımı olan bir engelleme yöntemini çağırmanın standart güzel bir yolu var mı? Yapabilmek istiyorum:
// call something.blockingMethod();
// if it hasn't come back within 2 seconds, forget it
Mantıklı geliyorsa.
Teşekkürler.
Java'da zaman aşımı olan bir engelleme yöntemini çağırmanın standart güzel bir yolu var mı? Yapabilmek istiyorum:
// call something.blockingMethod();
// if it hasn't come back within 2 seconds, forget it
Mantıklı geliyorsa.
Teşekkürler.
Yanıtlar:
Bir İnfazcı kullanabilirsiniz:
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
}
Eğer future.get
5 saniye içinde dönmez, bir atar TimeoutException
. Zaman aşımı saniye, dakika, milisaniye veya sabit olarak mevcut herhangi bir birim olarak yapılandırılabilir TimeUnit
.
Daha fazla ayrıntı için JavaDoc'a bakın .
BlockingMethodCallable
geçmek istediğiniz parametreleri kabul eden blockingMethod()
ve bunları üye değişkenler (muhtemelen son olarak) olarak depolayan adında yeni bir sınıf oluşturun . Sonra içeride call()
bu parametreleri blockMethod()
.
future.cancel(true)
- Future <Object> türündeki cancel (boolean) yöntemi arguments () için geçerli değil
Çağrıyı bir içine sarabilir ve FutureTask
get () 'nin zaman aşımı sürümünü kullanabilirsiniz.
Bkz. Http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/FutureTask.html
Ayrıca perde arkasında bir Executor kullanan Guava'nın TimeLimiter'ına bakınız .
İnsanların bunu pek çok şekilde uygulamaya çalışması gerçekten harika. Ama gerçek şu ki, hiçbir yolu yok.
Çoğu geliştirici, engelleme çağrısını farklı bir iş parçacığına koymaya ve bir geleceğe veya zamanlayıcıya sahip olmaya çalışır. ANCAK, iş parçacığı kesintisini açıkça işleyen Thread.sleep () ve Lock.lockInterruptously () yöntemleri gibi birkaç özel durum bir yana, Java'da bir iş parçacığını harici olarak durdurmanın bir yolu yoktur.
Yani gerçekten sadece 3 genel seçeneğiniz var:
Engelleme aramanızı yeni bir iş parçacığına koyun ve süre sona ererse, o ileti dizisini asılı bırakarak devam edin. Bu durumda, iş parçacığının bir Daemon iş parçacığı olacak şekilde ayarlandığından emin olmalısınız. Bu şekilde iş parçacığı uygulamanızın sonlandırılmasını durdurmaz.
Engellemeyen Java API'leri kullanın. Dolayısıyla, örneğin ağ için, NIO2'yi kullanın ve engellemeyen yöntemleri kullanın. Konsoldan okumak için, engellemeden önce Scanner.hasNext () öğesini kullanın.
Engelleme aramanız bir GÇ değilse, ancak mantığınızsa, Thread.isInterrupted()
harici olarak kesintiye uğrayıp uğramadığını tekrar tekrar kontrol edebilir thread.interrupt()
ve engelleme iş parçacığı üzerinde başka bir iş parçacığı çağrısı yapabilirsiniz .
Eşzamanlılık ile ilgili bu kurs https://www.udemy.com/java-multithreading-concurrency-performance-optimization/?couponCode=CONCURRENCY
Java'da nasıl çalıştığını gerçekten anlamak istiyorsanız, gerçekten bu temellerin üzerinden geçer. Aslında bu belirli sınırlamalar ve senaryolar hakkında ve derslerden birinde bunlardan nasıl bahsedileceği hakkında konuşuyor.
Mümkün olduğunca engelleme çağrıları kullanmadan kişisel olarak programlamaya çalışıyorum. Örneğin Vert.x gibi, IO işlemlerini eşzamansız olarak ve engellemesiz bir şekilde gerçekleştirmeyi gerçekten kolaylaştıran ve verimli kılan araç setleri vardır.
Umut ediyorum bu yardım eder
Bunun için jcabi-noktaları kitaplığı ile bir AspectJ çözümü de vardır .
@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
}
Daha kısa ve öz olamaz, ancak AspectJ'ye güvenmeniz ve tabii ki bunu geliştirme yaşam döngünüzde tanıtmanız gerekir.
Bunu daha ayrıntılı olarak açıklayan bir makale var: Java Yöntemi Yürütme Süresini Sınırlayın
Thread thread = new Thread(new Runnable() {
public void run() {
something.blockingMethod();
}
});
thread.start();
thread.join(2000);
if (thread.isAlive()) {
thread.stop();
}
Bu durdurmanın kullanımdan kaldırıldığını unutmayın, daha iyi bir alternatif, blockingMethod () içinde bazı geçici boole bayrakları ayarlamaktır, bunu kontrol edin ve şu şekilde çıkın:
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)");
}
}
}
Bunu dene. Daha basit çözüm. Blok zaman sınırı içinde çalışmazsa bunu garanti eder. süreç sona erecek ve bir istisna atacaktır.
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;
}
}
misal :
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
}
Size burada tam kodu veriyorum. Aradığım yöntemin yerine, yönteminizi kullanabilirsiniz:
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
Birkaç milisaniye uyuduğunu varsayalım :
public void blockingMethod(Object input) {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Benim çözümüm kullanmak wait()
ve bunun synchronized
gibi:
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();
}
}
}
Böylece değiştirebilirsin
something.blockingMethod(input)
-e
something.blockingMethod(input, 2000)
Umarım yardımcı olur.
GitHub'daki arıza korumalı projede bulunan gibi bir devre kesici uygulamasına ihtiyacınız var .