最简单的方法是使用Java 中已有的wait
和方法。notifyAll
您需要做的就是使用一个AtomicBoolean
作为标志并阻止它,直到另一个Thread
告诉您某些事情发生了变化。
这与您的方法之间的区别在于,阻塞线程不执行任何操作,而轮询线程使用 CPU 时间。
Thread
这是一个使用两个s的简单示例- 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
我已经return
在InterruptedException
块中使用过,您可能想要使用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
然后获取对the 的锁Lock
并调用which awake 。signalAll
Condition
First
First
然后重新获取锁并继续执行,打印“完成!”。
编辑
OP希望以doWorkAsync
指定的时间段调用该方法,如果该方法花费的时间少于该时间段,则该过程必须等待。如果该方法需要更长的时间,则应立即再次调用该方法。
任务需要在一定时间后停止。
该方法在任何时候都不应同时运行一次以上。
最简单的方法是从 a 调用该方法ScheduledExecutorService
,该Runnable
方法将包装该方法并调用- 阻塞调度get
的Future
执行程序,直到它完成。
这保证了至少 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);
最好的解决方案是Runnable
在 a上调用 rawScheduledExecutorService
而不是在另一个 executor 上调用它并在ListenableFuture
.