最簡單的方法是使用已在Java中的wait
和notifyAll
方法。您只需使用AtomicBoolean
作爲標誌並將其阻止,直到另一個Thread
告訴您某些內容已更改。
與您的方法之間的區別是阻塞的線程不會執行任何操作,而輪詢線程使用CPU時間。
下面是使用兩個Thread
個簡單的例子 - Runnable
「First
」提交併等待在done
直到Runnable
「Second
」通知它改變了標誌。
public class App {
private static final AtomicBoolean done = new AtomicBoolean(false);
private static final class First implements Runnable {
@Override
public void run() {
while (!done.get()) {
System.out.println("Waiting.");
synchronized (done) {
try {
done.wait();
} catch (InterruptedException ex) {
return;
}
}
}
System.out.println("Done!");
}
}
private static final class Second implements Runnable {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
return;
}
done.set(true);
synchronized (done) {
done.notifyAll();
}
}
}
public static void main(String[] args) throws InterruptedException {
final ExecutorService executorService = Executors.newFixedThreadPool(2);
executorService.submit(new First());
Thread.sleep(1000);
executorService.submit(new Second());
executorService.shutdown();
}
}
的sleep
電話是隻是爲了顯示任意長度的任務,可以發生,顯然他們不是必需的。
需要注意的是,First
每次打印「等待」它進入循環,如果運行代碼,它只打印一次。第二件要注意的事情是,First
立即響應標誌的變化,因爲它被告知在標誌改變時清醒並重新檢查。
我在InterruptedException
塊中使用了return
,您可能想要使用Thread.currentThread().interrupt()
,以便過程在虛假中斷時不會死亡。
一種更先進的方法是使用Lock
和Condition
public class App {
private static final Lock lock = new ReentrantLock();
private static final Condition condition = lock.newCondition();
private static final class First implements Runnable {
@Override
public void run() {
lock.lock();
System.out.println("Waiting");
try {
condition.await();
} catch (InterruptedException ex) {
return;
} finally {
lock.unlock();
}
System.out.println("Done!");
}
}
private static final class Second implements Runnable {
@Override
public void run() {
lock.lock();
try {
Thread.sleep(1000);
condition.signalAll();
} catch (InterruptedException ex) {
return;
} finally {
lock.unlock();
}
}
}
public static void main(String[] args) throws InterruptedException {
final ExecutorService executorService = Executors.newFixedThreadPool(2);
executorService.submit(new First());
Thread.sleep(1000);
executorService.submit(new Second());
executorService.shutdown();
}
}
在此情況下First
獲取Lock
對象上的鎖立即調用await
上Condition
。釋放鎖和Condition
上的塊。
Second
那麼獲取關於Lock
的鎖定和其上醒來First
的Condition
調用signalAll
。
First
然後重新獲得鎖定並繼續執行,打印「完成!」。
EDIT
的OP想與在指定時間要調用的方法doWorkAsync
,如果該方法花費較少的時間比,則週期的過程中必須等待。如果方法需要更長的時間,那麼應該立即再次調用該方法。
任務需要在一段時間後停止。
該方法不應該同時運行多次。
最簡單的方法是調用從ScheduledExecutorService
的方法,該Runnable
想包的方法和對Future
叫get
- 阻斷安排執行程序,直到它完成。
這保證用至少調用WAIT_TIME_BETWEEN_CALLS_SECS
延遲的方法。
然後計劃在設定時間後殺死第一個任務的另一個任務。
final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
final Future<?> taskHandle = scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
final ListenableFuture<Void> lf = doWorkAsync();
try {
doWorkAsync().get();
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
} catch (ExecutionException ex) {
throw new RuntimeException(ex);
}
}
}, 0, WAIT_TIME_BETWEEN_CALLS_SECS, TimeUnit.SECONDS);
scheduledExecutorService.schedule(new Runnable() {
@Override
public void run() {
taskHandle.cancel(false);
}
}, TOTAL_TIME_SECS, TimeUnit.SECONDS);
最好的解決辦法是調用一個ScheduledExecutorService
原始Runnable
,而不是調用它在另一個執行人及上阻塞ListenableFuture
。
以零超時加入異步工作的線程有什麼問題 – 2013-04-07 01:49:51
@EliAlgranti我不想阻塞。 Thread.join()將阻塞,直到異步任務完成。 – knightry 2013-04-07 04:51:53
你處於無限循環中,正在睡覺。阻塞如何成爲一個問題? – user949300 2013-04-07 06:57:43