java避免等待_java – 防止多个异步调用同时进行而不会...

最简单的方法是使用Java中已有的wait和notifyAll方法.您需要做的就是使用AtomicBoolean作为标志并阻止它,直到另一个Thread告诉您某些内容已更改.

它与您的方法之间的区别在于,阻塞的线程不执行任何操作,而轮询线程使用CPU时间.

下面是一个使用两个线程的简单示例 – 提交Runnable“First”并等待完成,直到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();

}

}

睡眠调用只是为了表明可以进行任意长度的任务,显然它们不是必需的.

需要注意的是,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对象的锁定,立即调用等待条件.释放条件上的锁和块.

然后第二次获取Lock上的锁定并在唤醒First的条件上调用signalAll.

首先重新获取锁定并继续执行,打印“完成!”.

编辑

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 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上阻塞.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值