@Test public void testTimeout() { final int destructAfterLastActivityInMs = 300; final SelfDestructiveThread thread = new SelfDestructiveThread( "test", Process.THREAD_PRIORITY_BACKGROUND, destructAfterLastActivityInMs); final int timeoutMs = 300; try { thread.postAndWait(new Callable<Object>() { @Override public Object call() throws Exception { waitMillis(timeoutMs * 3); return new Object(); } }, timeoutMs); fail(); } catch (InterruptedException e) { } }
public <T> T postAndWait(final Callable<T> callable, int timeoutMillis) throws InterruptedException { final ReentrantLock lock = new ReentrantLock(); final Condition cond = lock.newCondition(); final AtomicReference<T> holder = new AtomicReference(); final AtomicBoolean running = new AtomicBoolean(true); post(new Runnable() { @Override public void run() { try { holder.set(callable.call()); } catch (Exception e) { } lock.lock(); try { running.set(false); cond.signal(); } finally { lock.unlock(); } } }); lock.lock(); try { if (!running.get()) { return holder.get(); } long remaining = TimeUnit.MILLISECONDS.toNanos(timeoutMillis); for (;;) { try { remaining = cond.awaitNanos(remaining); } catch (InterruptedException e) { } if (!running.get()) { return holder.get(); } if (remaining <= 0) { throw new InterruptedException("timeout"); } } } finally { lock.unlock(); } }
SelfDestructiveThread { public <T> T postAndWait(final Callable<T> callable, int timeoutMillis) throws InterruptedException { final ReentrantLock lock = new ReentrantLock(); final Condition cond = lock.newCondition(); final AtomicReference<T> holder = new AtomicReference(); final AtomicBoolean running = new AtomicBoolean(true); post(new Runnable() { @Override public void run() { try { holder.set(callable.call()); } catch (Exception e) { } lock.lock(); try { running.set(false); cond.signal(); } finally { lock.unlock(); } } }); lock.lock(); try { if (!running.get()) { return holder.get(); } long remaining = TimeUnit.MILLISECONDS.toNanos(timeoutMillis); for (;;) { try { remaining = cond.awaitNanos(remaining); } catch (InterruptedException e) { } if (!running.get()) { return holder.get(); } if (remaining <= 0) { throw new InterruptedException("timeout"); } } } finally { lock.unlock(); } } }
SelfDestructiveThread { public <T> T postAndWait(final Callable<T> callable, int timeoutMillis) throws InterruptedException { final ReentrantLock lock = new ReentrantLock(); final Condition cond = lock.newCondition(); final AtomicReference<T> holder = new AtomicReference(); final AtomicBoolean running = new AtomicBoolean(true); post(new Runnable() { @Override public void run() { try { holder.set(callable.call()); } catch (Exception e) { } lock.lock(); try { running.set(false); cond.signal(); } finally { lock.unlock(); } } }); lock.lock(); try { if (!running.get()) { return holder.get(); } long remaining = TimeUnit.MILLISECONDS.toNanos(timeoutMillis); for (;;) { try { remaining = cond.awaitNanos(remaining); } catch (InterruptedException e) { } if (!running.get()) { return holder.get(); } if (remaining <= 0) { throw new InterruptedException("timeout"); } } } finally { lock.unlock(); } } SelfDestructiveThread(
            String threadName, int priority, int destructAfterMillisec); }
SelfDestructiveThread { public <T> T postAndWait(final Callable<T> callable, int timeoutMillis) throws InterruptedException { final ReentrantLock lock = new ReentrantLock(); final Condition cond = lock.newCondition(); final AtomicReference<T> holder = new AtomicReference(); final AtomicBoolean running = new AtomicBoolean(true); post(new Runnable() { @Override public void run() { try { holder.set(callable.call()); } catch (Exception e) { } lock.lock(); try { running.set(false); cond.signal(); } finally { lock.unlock(); } } }); lock.lock(); try { if (!running.get()) { return holder.get(); } long remaining = TimeUnit.MILLISECONDS.toNanos(timeoutMillis); for (;;) { try { remaining = cond.awaitNanos(remaining); } catch (InterruptedException e) { } if (!running.get()) { return holder.get(); } if (remaining <= 0) { throw new InterruptedException("timeout"); } } } finally { lock.unlock(); } } SelfDestructiveThread(
            String threadName, int priority, int destructAfterMillisec); @VisibleForTesting boolean isRunning(); @VisibleForTesting int getGeneration(); void postAndReply(final Callable<T> callable, final ReplyCallback<T> reply); T postAndWait(final Callable<T> callable, int timeoutMillis); }
SelfDestructiveThread { public <T> T postAndWait(final Callable<T> callable, int timeoutMillis) throws InterruptedException { final ReentrantLock lock = new ReentrantLock(); final Condition cond = lock.newCondition(); final AtomicReference<T> holder = new AtomicReference(); final AtomicBoolean running = new AtomicBoolean(true); post(new Runnable() { @Override public void run() { try { holder.set(callable.call()); } catch (Exception e) { } lock.lock(); try { running.set(false); cond.signal(); } finally { lock.unlock(); } } }); lock.lock(); try { if (!running.get()) { return holder.get(); } long remaining = TimeUnit.MILLISECONDS.toNanos(timeoutMillis); for (;;) { try { remaining = cond.awaitNanos(remaining); } catch (InterruptedException e) { } if (!running.get()) { return holder.get(); } if (remaining <= 0) { throw new InterruptedException("timeout"); } } } finally { lock.unlock(); } } SelfDestructiveThread(
            String threadName, int priority, int destructAfterMillisec); @VisibleForTesting boolean isRunning(); @VisibleForTesting int getGeneration(); void postAndReply(final Callable<T> callable, final ReplyCallback<T> reply); T postAndWait(final Callable<T> callable, int timeoutMillis);  }