私の経験では、タイムアウトはタイムクリティカルではないなどのように任意に選択されます。1000ミリ秒のタイムアウトを選択し、代わりに1001ミリ秒かかる場合、影響はわずかです。タイムアウトを実装するには、実装をできるだけ単純にすることをお勧めします。
ScheduledExecutorServiceを使用してタイムアウトを実装できます。
final ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor();
public void addTimeoutForTask(final Future future, int timeOutMS) {
ses.schedule(new Runnable() {
@Override
public void run() {
future.cancel(true);
}
}, timeOutMS, TimeUnit.MILLISECONDS);
}
非ブロッキング操作を実行していて、これをタイムアウトさせたい場合は、実行できます。
interface TimedPoller {
public void poll();
/**
* @return is it now closed.
*/
public boolean checkTimeout(long nowNS);
}
private final Set<TimedPoller> timedPollers = new LinkedHashSet<>();
private volatile TimedPoller[] timedPollersArray = {};
public void add(TimedPoller timedPoller) {
synchronized (timedPollers) {
long nowNS = System.nanoTime();
if (!timedPoller.checkTimeout(nowNS) && timedPollers.add(timedPoller))
timedPollersArray = timedPollers.toArray(new TimedPoller[timedPollers.size());
}
}
public void remove(TimedPoller timedPoller) {
synchronized (timedPollers) {
if (timedPollers.remove(timedPoller))
timedPollersArray = timedPollers.toArray(new TimedPoller[timedPollers.size());
}
}
private volatile boolean running = true;
public void run() {
while (running) {
// check the timeout for every 1000 polls.
for (int i = 0; i < 1000; i += timedPollersArray.length) {
TimedPoller[] pollers = timedPollersArray;
for (TimedPoller poller : pollers) {
poller.poll();
}
}
long nowNS = System.nanoTime();
TimedPoller[] pollers = timedPollersArray;
for (TimedPoller poller : pollers) {
if (poller.checkTimeout(nowNS))
remove(poller);
}
}
}
CPUをあきらめるか、あきらめないかのどちらかです。CPUをあきらめると、他のスレッドを実行できますが、再度実行できるようになるまでに遅延が発生します。または、応答時間を改善するCPUをあきらめませんが、別のスレッドを実行できません。
CPUをあきらめることなく、他のものを実行できるようにしたいと考えているようです。これは些細なことではありませんが、正しく実行された場合は両方の利点のいくつかを提供できます(または効率的に実行されなかった場合は両方の最悪の場合)
実行できることは、小さなタスクがたくさんある場合に独自のスレッドロジックを実装することです。たとえば、1つのCPUだけで使用できる10個の項目をポーリングする場合などです。