001/*
002 * This file is a modified version of
003 * http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/main/java/util/concurrent/AbstractExecutorService.java?revision=1.35
004 * which contained the following notice:
005 *
006 * Written by Doug Lea with assistance from members of JCP JSR-166 Expert Group and released to the
007 * public domain, as explained at http://creativecommons.org/publicdomain/zero/1.0/
008 *
009 * Rationale for copying:
010 * Guava targets JDK5, whose AbstractExecutorService class lacks the newTaskFor protected
011 * customization methods needed by MoreExecutors.listeningDecorator. This class is a copy of
012 * AbstractExecutorService from the JSR166 CVS repository. It contains the desired methods.
013 */
014
015package com.google.common.util.concurrent;
016
017import static com.google.common.util.concurrent.MoreExecutors.invokeAnyImpl;
018
019import com.google.common.annotations.Beta;
020
021import java.util.ArrayList;
022import java.util.Collection;
023import java.util.Iterator;
024import java.util.List;
025import java.util.concurrent.Callable;
026import java.util.concurrent.CancellationException;
027import java.util.concurrent.ExecutionException;
028import java.util.concurrent.Future;
029import java.util.concurrent.TimeUnit;
030import java.util.concurrent.TimeoutException;
031
032import javax.annotation.Nullable;
033
034/**
035 * Implements {@link ListeningExecutorService} execution methods atop the abstract {@link #execute}
036 * method. More concretely, the {@code submit}, {@code invokeAny} and {@code invokeAll} methods
037 * create {@link ListenableFutureTask} instances and pass them to {@link #execute}.
038 *
039 * <p>In addition to {@link #execute}, subclasses must implement all methods related to shutdown and
040 * termination.
041 *
042 * @author Doug Lea
043 * @since 14.0
044 */
045@Beta
046public abstract class AbstractListeningExecutorService implements ListeningExecutorService {
047  @Override
048  public ListenableFuture<?> submit(Runnable task) {
049    ListenableFutureTask<Void> ftask = ListenableFutureTask.create(task, null);
050    execute(ftask);
051    return ftask;
052  }
053
054  @Override
055  public <T> ListenableFuture<T> submit(Runnable task, @Nullable T result) {
056    ListenableFutureTask<T> ftask = ListenableFutureTask.create(task, result);
057    execute(ftask);
058    return ftask;
059  }
060
061  @Override
062  public <T> ListenableFuture<T> submit(Callable<T> task) {
063    ListenableFutureTask<T> ftask = ListenableFutureTask.create(task);
064    execute(ftask);
065    return ftask;
066  }
067
068  @Override
069  public <T> T invokeAny(Collection<? extends Callable<T>> tasks) throws InterruptedException,
070      ExecutionException {
071    try {
072      return invokeAnyImpl(this, tasks, false, 0);
073    } catch (TimeoutException cannotHappen) {
074      throw new AssertionError();
075    }
076  }
077
078  @Override
079  public <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)
080      throws InterruptedException, ExecutionException, TimeoutException {
081    return invokeAnyImpl(this, tasks, true, unit.toNanos(timeout));
082  }
083
084  @Override
085  public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
086      throws InterruptedException {
087    if (tasks == null) {
088      throw new NullPointerException();
089    }
090    List<Future<T>> futures = new ArrayList<Future<T>>(tasks.size());
091    boolean done = false;
092    try {
093      for (Callable<T> t : tasks) {
094        ListenableFutureTask<T> f = ListenableFutureTask.create(t);
095        futures.add(f);
096        execute(f);
097      }
098      for (Future<T> f : futures) {
099        if (!f.isDone()) {
100          try {
101            f.get();
102          } catch (CancellationException ignore) {} catch (ExecutionException ignore) {}
103        }
104      }
105      done = true;
106      return futures;
107    } finally {
108      if (!done) {
109        for (Future<T> f : futures) {
110          f.cancel(true);
111        }
112      }
113    }
114  }
115
116  @Override
117  public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout,
118      TimeUnit unit) throws InterruptedException {
119    if (tasks == null || unit == null) {
120      throw new NullPointerException();
121    }
122    long nanos = unit.toNanos(timeout);
123    List<Future<T>> futures = new ArrayList<Future<T>>(tasks.size());
124    boolean done = false;
125    try {
126      for (Callable<T> t : tasks) {
127        futures.add(ListenableFutureTask.create(t));
128      }
129
130      long lastTime = System.nanoTime();
131
132      // Interleave time checks and calls to execute in case
133      // executor doesn't have any/much parallelism.
134      Iterator<Future<T>> it = futures.iterator();
135      while (it.hasNext()) {
136        execute((Runnable) (it.next()));
137        long now = System.nanoTime();
138        nanos -= now - lastTime;
139        lastTime = now;
140        if (nanos <= 0) {
141          return futures;
142        }
143      }
144
145      for (Future<T> f : futures) {
146        if (!f.isDone()) {
147          if (nanos <= 0) {
148            return futures;
149          }
150          try {
151            f.get(nanos, TimeUnit.NANOSECONDS);
152          } catch (CancellationException ignore) {} catch (ExecutionException ignore) {} catch (TimeoutException toe) {
153            return futures;
154          }
155          long now = System.nanoTime();
156          nanos -= now - lastTime;
157          lastTime = now;
158        }
159      }
160      done = true;
161      return futures;
162    } finally {
163      if (!done) {
164        for (Future<T> f : futures) {
165          f.cancel(true);
166        }
167      }
168    }
169  }
170}