Android中使用Executors創建線程池的方式

先來看一下Executors類在Android系統中的源碼定義:

package java.util.concurrent;

import java.security.AccessControlContext;
import java.security.AccessControlException;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import sun.security.util.SecurityConstants;

// BEGIN android-note
// removed security manager docs
// END android-note

/**
 * Factory and utility methods for {@link Executor}, {@link
 * ExecutorService}, {@link ScheduledExecutorService}, {@link
 * ThreadFactory}, and {@link Callable} classes defined in this
 * package. This class supports the following kinds of methods:
 *
 * <ul>
 *   <li>Methods that create and return an {@link ExecutorService}
 *       set up with commonly useful configuration settings.
 *   <li>Methods that create and return a {@link ScheduledExecutorService}
 *       set up with commonly useful configuration settings.
 *   <li>Methods that create and return a "wrapped" ExecutorService, that
 *       disables reconfiguration by making implementation-specific methods
 *       inaccessible.
 *   <li>Methods that create and return a {@link ThreadFactory}
 *       that sets newly created threads to a known state.
 *   <li>Methods that create and return a {@link Callable}
 *       out of other closure-like forms, so they can be used
 *       in execution methods requiring {@code Callable}.
 * </ul>
 *
 * @since 1.5
 * @author Doug Lea
 */
public class Executors {

    /**
     * Creates a thread pool that reuses a fixed number of threads
     * operating off a shared unbounded queue.  At any point, at most
     * {@code nThreads} threads will be active processing tasks.
     * If additional tasks are submitted when all threads are active,
     * they will wait in the queue until a thread is available.
     * If any thread terminates due to a failure during execution
     * prior to shutdown, a new one will take its place if needed to
     * execute subsequent tasks.  The threads in the pool will exist
     * until it is explicitly {@link ExecutorService#shutdown shutdown}.
     *
     * @param nThreads the number of threads in the pool
     * @return the newly created thread pool
     * @throws IllegalArgumentException if {@code nThreads <= 0}
     */
    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

    /**
     * Creates a thread pool that maintains enough threads to support
     * the given parallelism level, and may use multiple queues to
     * reduce contention. The parallelism level corresponds to the
     * maximum number of threads actively engaged in, or available to
     * engage in, task processing. The actual number of threads may
     * grow and shrink dynamically. A work-stealing pool makes no
     * guarantees about the order in which submitted tasks are
     * executed.
     *
     * @param parallelism the targeted parallelism level
     * @return the newly created thread pool
     * @throws IllegalArgumentException if {@code parallelism <= 0}
     * @since 1.8
     */
    public static ExecutorService newWorkStealingPool(int parallelism) {
        return new ForkJoinPool
            (parallelism,
             ForkJoinPool.defaultForkJoinWorkerThreadFactory,
             null, true);
    }

    /**
     * Creates a work-stealing thread pool using the number of
     * {@linkplain Runtime#availableProcessors available processors}
     * as its target parallelism level.
     *
     * @return the newly created thread pool
     * @see #newWorkStealingPool(int)
     * @since 1.8
     */
    public static ExecutorService newWorkStealingPool() {
        return new ForkJoinPool
            (Runtime.getRuntime().availableProcessors(),
             ForkJoinPool.defaultForkJoinWorkerThreadFactory,
             null, true);
    }

    /**
     * Creates a thread pool that reuses a fixed number of threads
     * operating off a shared unbounded queue, using the provided
     * ThreadFactory to create new threads when needed.  At any point,
     * at most {@code nThreads} threads will be active processing
     * tasks.  If additional tasks are submitted when all threads are
     * active, they will wait in the queue until a thread is
     * available.  If any thread terminates due to a failure during
     * execution prior to shutdown, a new one will take its place if
     * needed to execute subsequent tasks.  The threads in the pool will
     * exist until it is explicitly {@link ExecutorService#shutdown
     * shutdown}.
     *
     * @param nThreads the number of threads in the pool
     * @param threadFactory the factory to use when creating new threads
     * @return the newly created thread pool
     * @throws NullPointerException if threadFactory is null
     * @throws IllegalArgumentException if {@code nThreads <= 0}
     */
    public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>(),
                                      threadFactory);
    }

    /**
     * Creates an Executor that uses a single worker thread operating
     * off an unbounded queue. (Note however that if this single
     * thread terminates due to a failure during execution prior to
     * shutdown, a new one will take its place if needed to execute
     * subsequent tasks.)  Tasks are guaranteed to execute
     * sequentially, and no more than one task will be active at any
     * given time. Unlike the otherwise equivalent
     * {@code newFixedThreadPool(1)} the returned executor is
     * guaranteed not to be reconfigurable to use additional threads.
     *
     * @return the newly created single-threaded Executor
     */
    public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

    /**
     * Creates an Executor that uses a single worker thread operating
     * off an unbounded queue, and uses the provided ThreadFactory to
     * create a new thread when needed. Unlike the otherwise
     * equivalent {@code newFixedThreadPool(1, threadFactory)} the
     * returned executor is guaranteed not to be reconfigurable to use
     * additional threads.
     *
     * @param threadFactory the factory to use when creating new
     * threads
     *
     * @return the newly created single-threaded Executor
     * @throws NullPointerException if threadFactory is null
     */
    public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>(),
                                    threadFactory));
    }

    /**
     * Creates a thread pool that creates new threads as needed, but
     * will reuse previously constructed threads when they are
     * available.  These pools will typically improve the performance
     * of programs that execute many short-lived asynchronous tasks.
     * Calls to {@code execute} will reuse previously constructed
     * threads if available. If no existing thread is available, a new
     * thread will be created and added to the pool. Threads that have
     * not been used for sixty seconds are terminated and removed from
     * the cache. Thus, a pool that remains idle for long enough will
     * not consume any resources. Note that pools with similar
     * properties but different details (for example, timeout parameters)
     * may be created using {@link ThreadPoolExecutor} constructors.
     *
     * @return the newly created thread pool
     */
    public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }

    /**
     * Creates a thread pool that creates new threads as needed, but
     * will reuse previously constructed threads when they are
     * available, and uses the provided
     * ThreadFactory to create new threads when needed.
     * @param threadFactory the factory to use when creating new threads
     * @return the newly created thread pool
     * @throws NullPointerException if threadFactory is null
     */
    public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>(),
                                      threadFactory);
    }

    /**
     * Creates a single-threaded executor that can schedule commands
     * to run after a given delay, or to execute periodically.
     * (Note however that if this single
     * thread terminates due to a failure during execution prior to
     * shutdown, a new one will take its place if needed to execute
     * subsequent tasks.)  Tasks are guaranteed to execute
     * sequentially, and no more than one task will be active at any
     * given time. Unlike the otherwise equivalent
     * {@code newScheduledThreadPool(1)} the returned executor is
     * guaranteed not to be reconfigurable to use additional threads.
     * @return the newly created scheduled executor
     */
    public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
        return new DelegatedScheduledExecutorService
            (new ScheduledThreadPoolExecutor(1));
    }

    /**
     * Creates a single-threaded executor that can schedule commands
     * to run after a given delay, or to execute periodically.  (Note
     * however that if this single thread terminates due to a failure
     * during execution prior to shutdown, a new one will take its
     * place if needed to execute subsequent tasks.)  Tasks are
     * guaranteed to execute sequentially, and no more than one task
     * will be active at any given time. Unlike the otherwise
     * equivalent {@code newScheduledThreadPool(1, threadFactory)}
     * the returned executor is guaranteed not to be reconfigurable to
     * use additional threads.
     * @param threadFactory the factory to use when creating new
     * threads
     * @return a newly created scheduled executor
     * @throws NullPointerException if threadFactory is null
     */
    public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory) {
        return new DelegatedScheduledExecutorService
            (new ScheduledThreadPoolExecutor(1, threadFactory));
    }

    /**
     * Creates a thread pool that can schedule commands to run after a
     * given delay, or to execute periodically.
     * @param corePoolSize the number of threads to keep in the pool,
     * even if they are idle
     * @return a newly created scheduled thread pool
     * @throws IllegalArgumentException if {@code corePoolSize < 0}
     */
    public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
        return new ScheduledThreadPoolExecutor(corePoolSize);
    }

    /**
     * Creates a thread pool that can schedule commands to run after a
     * given delay, or to execute periodically.
     * @param corePoolSize the number of threads to keep in the pool,
     * even if they are idle
     * @param threadFactory the factory to use when the executor
     * creates a new thread
     * @return a newly created scheduled thread pool
     * @throws IllegalArgumentException if {@code corePoolSize < 0}
     * @throws NullPointerException if threadFactory is null
     */
    public static ScheduledExecutorService newScheduledThreadPool(
            int corePoolSize, ThreadFactory threadFactory) {
        return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
    }

    /**
     * Returns an object that delegates all defined {@link
     * ExecutorService} methods to the given executor, but not any
     * other methods that might otherwise be accessible using
     * casts. This provides a way to safely "freeze" configuration and
     * disallow tuning of a given concrete implementation.
     * @param executor the underlying implementation
     * @return an {@code ExecutorService} instance
     * @throws NullPointerException if executor null
     */
    public static ExecutorService unconfigurableExecutorService(ExecutorService executor) {
        if (executor == null)
            throw new NullPointerException();
        return new DelegatedExecutorService(executor);
    }

    /**
     * Returns an object that delegates all defined {@link
     * ScheduledExecutorService} methods to the given executor, but
     * not any other methods that might otherwise be accessible using
     * casts. This provides a way to safely "freeze" configuration and
     * disallow tuning of a given concrete implementation.
     * @param executor the underlying implementation
     * @return a {@code ScheduledExecutorService} instance
     * @throws NullPointerException if executor null
     */
    public static ScheduledExecutorService unconfigurableScheduledExecutorService(ScheduledExecutorService executor) {
        if (executor == null)
            throw new NullPointerException();
        return new DelegatedScheduledExecutorService(executor);
    }

    /**
     * Returns a default thread factory used to create new threads.
     * This factory creates all new threads used by an Executor in the
     * same {@link ThreadGroup}. Each new
     * thread is created as a non-daemon thread with priority set to
     * the smaller of {@code Thread.NORM_PRIORITY} and the maximum
     * priority permitted in the thread group.  New threads have names
     * accessible via {@link Thread#getName} of
     * <em>pool-N-thread-M</em>, where <em>N</em> is the sequence
     * number of this factory, and <em>M</em> is the sequence number
     * of the thread created by this factory.
     * @return a thread factory
     */
    public static ThreadFactory defaultThreadFactory() {
        return new DefaultThreadFactory();
    }

    /**
     * Legacy security code; do not use.
     */
    public static ThreadFactory privilegedThreadFactory() {
        return new PrivilegedThreadFactory();
    }

    /**
     * Returns a {@link Callable} object that, when
     * called, runs the given task and returns the given result.  This
     * can be useful when applying methods requiring a
     * {@code Callable} to an otherwise resultless action.
     * @param task the task to run
     * @param result the result to return
     * @param <T> the type of the result
     * @return a callable object
     * @throws NullPointerException if task null
     */
    public static <T> Callable<T> callable(Runnable task, T result) {
        if (task == null)
            throw new NullPointerException();
        return new RunnableAdapter<T>(task, result);
    }

    /**
     * Returns a {@link Callable} object that, when
     * called, runs the given task and returns {@code null}.
     * @param task the task to run
     * @return a callable object
     * @throws NullPointerException if task null
     */
    public static Callable<Object> callable(Runnable task) {
        if (task == null)
            throw new NullPointerException();
        return new RunnableAdapter<Object>(task, null);
    }

    /**
     * Returns a {@link Callable} object that, when
     * called, runs the given privileged action and returns its result.
     * @param action the privileged action to run
     * @return a callable object
     * @throws NullPointerException if action null
     */
    public static Callable<Object> callable(final PrivilegedAction<?> action) {
        if (action == null)
            throw new NullPointerException();
        return new Callable<Object>() {
            public Object call() { return action.run(); }};
    }

    /**
     * Returns a {@link Callable} object that, when
     * called, runs the given privileged exception action and returns
     * its result.
     * @param action the privileged exception action to run
     * @return a callable object
     * @throws NullPointerException if action null
     */
    public static Callable<Object> callable(final PrivilegedExceptionAction<?> action) {
        if (action == null)
            throw new NullPointerException();
        return new Callable<Object>() {
            public Object call() throws Exception { return action.run(); }};
    }

    /**
     * Legacy security code; do not use.
     */
    public static <T> Callable<T> privilegedCallable(Callable<T> callable) {
        if (callable == null)
            throw new NullPointerException();
        return new PrivilegedCallable<T>(callable);
    }

    /**
     * Legacy security code; do not use.
     */
    public static <T> Callable<T> privilegedCallableUsingCurrentClassLoader(Callable<T> callable) {
        if (callable == null)
            throw new NullPointerException();
        return new PrivilegedCallableUsingCurrentClassLoader<T>(callable);
    }

    // Non-public classes supporting the public methods

    /**
     * A callable that runs given task and returns given result.
     */
    private static final class RunnableAdapter<T> implements Callable<T> {
        private final Runnable task;
        private final T result;
        RunnableAdapter(Runnable task, T result) {
            this.task = task;
            this.result = result;
        }
        public T call() {
            task.run();
            return result;
        }
    }

    /**
     * A callable that runs under established access control settings.
     */
    private static final class PrivilegedCallable<T> implements Callable<T> {
        final Callable<T> task;
        final AccessControlContext acc;

        PrivilegedCallable(Callable<T> task) {
            this.task = task;
            this.acc = AccessController.getContext();
        }

        public T call() throws Exception {
            try {
                return AccessController.doPrivileged(
                    new PrivilegedExceptionAction<T>() {
                        public T run() throws Exception {
                            return task.call();
                        }
                    }, acc);
            } catch (PrivilegedActionException e) {
                throw e.getException();
            }
        }
    }

    /**
     * A callable that runs under established access control settings and
     * current ClassLoader.
     */
    private static final class PrivilegedCallableUsingCurrentClassLoader<T>
            implements Callable<T> {
        final Callable<T> task;
        final AccessControlContext acc;
        final ClassLoader ccl;

        PrivilegedCallableUsingCurrentClassLoader(Callable<T> task) {
            // BEGIN Android-removed
            // SecurityManager sm = System.getSecurityManager();
            // if (sm != null) {
            //     // Calls to getContextClassLoader from this class
            //     // never trigger a security check, but we check
            //     // whether our callers have this permission anyways.
            //     sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);

            //     // Whether setContextClassLoader turns out to be necessary
            //     // or not, we fail fast if permission is not available.
            //     sm.checkPermission(new RuntimePermission("setContextClassLoader"));
            // }
            // END Android-removed
            this.task = task;
            this.acc = AccessController.getContext();
            this.ccl = Thread.currentThread().getContextClassLoader();
        }

        public T call() throws Exception {
            try {
                return AccessController.doPrivileged(
                    new PrivilegedExceptionAction<T>() {
                        public T run() throws Exception {
                            Thread t = Thread.currentThread();
                            ClassLoader cl = t.getContextClassLoader();
                            if (ccl == cl) {
                                return task.call();
                            } else {
                                t.setContextClassLoader(ccl);
                                try {
                                    return task.call();
                                } finally {
                                    t.setContextClassLoader(cl);
                                }
                            }
                        }
                    }, acc);
            } catch (PrivilegedActionException e) {
                throw e.getException();
            }
        }
    }

    /**
     * The default thread factory.
     */
    private static class DefaultThreadFactory implements ThreadFactory {
        private static final AtomicInteger poolNumber = new AtomicInteger(1);
        private final ThreadGroup group;
        private final AtomicInteger threadNumber = new AtomicInteger(1);
        private final String namePrefix;

        DefaultThreadFactory() {
            SecurityManager s = System.getSecurityManager();
            group = (s != null) ? s.getThreadGroup() :
                                  Thread.currentThread().getThreadGroup();
            namePrefix = "pool-" +
                          poolNumber.getAndIncrement() +
                         "-thread-";
        }

        public Thread newThread(Runnable r) {
            Thread t = new Thread(group, r,
                                  namePrefix + threadNumber.getAndIncrement(),
                                  0);
            if (t.isDaemon())
                t.setDaemon(false);
            if (t.getPriority() != Thread.NORM_PRIORITY)
                t.setPriority(Thread.NORM_PRIORITY);
            return t;
        }
    }

    /**
     * Thread factory capturing access control context and class loader.
     */
    private static class PrivilegedThreadFactory extends DefaultThreadFactory {
        final AccessControlContext acc;
        final ClassLoader ccl;

        PrivilegedThreadFactory() {
            super();
            // BEGIN Android-removed
            // SecurityManager sm = System.getSecurityManager();
            // if (sm != null) {
            //     // Calls to getContextClassLoader from this class
            //     // never trigger a security check, but we check
            //     // whether our callers have this permission anyways.
            //     sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);

            //     // Fail fast
            //     sm.checkPermission(new RuntimePermission("setContextClassLoader"));
            // }
            // END Android-removed
            this.acc = AccessController.getContext();
            this.ccl = Thread.currentThread().getContextClassLoader();
        }

        public Thread newThread(final Runnable r) {
            return super.newThread(new Runnable() {
                public void run() {
                    AccessController.doPrivileged(new PrivilegedAction<Void>() {
                        public Void run() {
                            Thread.currentThread().setContextClassLoader(ccl);
                            r.run();
                            return null;
                        }
                    }, acc);
                }
            });
        }
    }

    /**
     * A wrapper class that exposes only the ExecutorService methods
     * of an ExecutorService implementation.
     */
    private static class DelegatedExecutorService
            extends AbstractExecutorService {
        private final ExecutorService e;
        DelegatedExecutorService(ExecutorService executor) { e = executor; }
        public void execute(Runnable command) { e.execute(command); }
        public void shutdown() { e.shutdown(); }
        public List<Runnable> shutdownNow() { return e.shutdownNow(); }
        public boolean isShutdown() { return e.isShutdown(); }
        public boolean isTerminated() { return e.isTerminated(); }
        public boolean awaitTermination(long timeout, TimeUnit unit)
            throws InterruptedException {
            return e.awaitTermination(timeout, unit);
        }
        public Future<?> submit(Runnable task) {
            return e.submit(task);
        }
        public <T> Future<T> submit(Callable<T> task) {
            return e.submit(task);
        }
        public <T> Future<T> submit(Runnable task, T result) {
            return e.submit(task, result);
        }
        public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
            throws InterruptedException {
            return e.invokeAll(tasks);
        }
        public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
                                             long timeout, TimeUnit unit)
            throws InterruptedException {
            return e.invokeAll(tasks, timeout, unit);
        }
        public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
            throws InterruptedException, ExecutionException {
            return e.invokeAny(tasks);
        }
        public <T> T invokeAny(Collection<? extends Callable<T>> tasks,
                               long timeout, TimeUnit unit)
            throws InterruptedException, ExecutionException, TimeoutException {
            return e.invokeAny(tasks, timeout, unit);
        }
    }

    private static class FinalizableDelegatedExecutorService
            extends DelegatedExecutorService {
        FinalizableDelegatedExecutorService(ExecutorService executor) {
            super(executor);
        }
        protected void finalize() {
            super.shutdown();
        }
    }

    /**
     * A wrapper class that exposes only the ScheduledExecutorService
     * methods of a ScheduledExecutorService implementation.
     */
    private static class DelegatedScheduledExecutorService
            extends DelegatedExecutorService
            implements ScheduledExecutorService {
        private final ScheduledExecutorService e;
        DelegatedScheduledExecutorService(ScheduledExecutorService executor) {
            super(executor);
            e = executor;
        }
        public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) {
            return e.schedule(command, delay, unit);
        }
        public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) {
            return e.schedule(callable, delay, unit);
        }
        public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) {
            return e.scheduleAtFixedRate(command, initialDelay, period, unit);
        }
        public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) {
            return e.scheduleWithFixedDelay(command, initialDelay, delay, unit);
        }
    }

    /** Cannot instantiate. */
    private Executors() {}
}

 Executors 類究竟是如何使用的?

1. newFixedThreadPool,創建定長線程池,每當提交一個任務就創建一個線程,直到達到線程池的最大數量,這時線程數量不再變化。當某個任務執行結束後會釋放線程使其處於空閒狀態,如果有其他任務在等待執行,可以獲取這個空閒的線程資源,執行耗時任務。當線程發生錯誤結束時,線程池會補充一個新的線程。

看下面這個例子:創建一個工作線程數爲3的線程池,然後提交4個工作任務:

package com.xw.executosmultithreaddemo;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        testNewFixedThreadPool();
    }

    private void testNewFixedThreadPool(){
        //創建工作線程數爲 3 的線程池,每當提交一個任務就創建一個線程,直到達到線程池的最大數量,這時線程數量不再變化,當線程發生錯誤結束時,線程池會補充一個新的線程
        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
        //提交 4個任務
        fixedThreadPool.execute(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 8; i++) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+" A" + "===" + i);
                }
                System.out.println(Thread.currentThread().getName()+" A" + "任務結束.....");
            }
        });
        fixedThreadPool.execute(new Runnable() {

            @Override
            public void run() {
                for (int i = 0; i < 8; i++) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+" B" + "===" + i);
                }
                System.out.println(Thread.currentThread().getName()+" B" + "任務結束.....");
            }
        });
        fixedThreadPool.execute(new Runnable() {

            @Override
            public void run() {
                for (int i = 0; i < 8; i++) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+" C" + "===" + i);
                }
                System.out.println(Thread.currentThread().getName()+" C" + "任務結束.....");
            }
        });
        fixedThreadPool.execute(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 8; i++) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+" D" + "===" + i);
                }
                System.out.println(Thread.currentThread().getName()+" D" + "任務結束.....");
            }
        });

        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //關閉線程池後,已提交的任務仍然會執行完
        System.out.println("開始關閉線程池."+System.currentTimeMillis());
        fixedThreadPool.shutdown();
        System.out.println("關閉線程池完畢."+System.currentTimeMillis());
    }
}

上面的代碼因爲創建一個工作線程數爲3的線程池,然後創建了標記爲A、B、C、D的4個工作任務。首先創建提交的前三個工作任務A、B、C被3個子線程幾乎同時處理了(每個1秒打印一個數字)。當第四秒時調用了關閉線程池的方法shutdown(),但這個線程池以及開啓的任務任然還可以執行,以及的在隊列中排隊等待的第四個工作任務D也都可以被執行,直到所有任務結束才關閉線程池。A、B、C任務繼續執行打印數字,直到pool-2-thread-2 B任務結束,空閒出一個線程被正在隊列等待的任務D獲取、執行打印任務。所以任務D的線程名爲:pool-2-thread-2。

輸出結果:

com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===0
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-2 B===0
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-3 C===0

com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===1
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-2 B===1
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-3 C===1

com.xw.executosmultithreaddemo I/System.out: pool-2-thread-2 B===2
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===2
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-3 C===2

com.xw.executosmultithreaddemo I/System.out: pool-2-thread-2 B===3
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===3
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-3 C===3

com.xw.executosmultithreaddemo I/System.out: pool-2-thread-2 B===4
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-3 C===4
com.xw.executosmultithreaddemo I/System.out: 開始關閉線程池.1592558042796
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===4
com.xw.executosmultithreaddemo I/System.out: 關閉線程池完畢.1592558042797

com.xw.executosmultithreaddemo I/System.out: pool-2-thread-2 B===5
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-3 C===5
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===5

com.xw.executosmultithreaddemo I/System.out: pool-2-thread-2 B===6
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-3 C===6
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===6

com.xw.executosmultithreaddemo I/System.out: pool-2-thread-2 B===7
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-2 B任務結束.....
//上面一行,可以看出pool-2-thread-2 B 先結束任務,線程被釋放,此時在隊列等待的任務D 立即獲得這個線程資源執行打印任務
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-3 C===7
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-3 C任務結束.....
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===7
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A任務結束.....
//pool-2-thread-2 ---> D
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-2 D===0
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-2 D===1
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-2 D===2
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-2 D===3
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-2 D===4
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-2 D===5
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-2 D===6
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-2 D===7
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-2 D任務結束.....

2. newCachedThreadPool,創建可緩存的線程池,如果線程池的容量超過了任務數,自動回收空閒線程,任務增加時可以自動添加新線程,線程池的容量不限制。

創建可緩存的線程池,不需要指定線程的數量,創建4個工作任務後,線程開始工作,在第五秒後新建第5個工作任務,可以看出這5個線程一起併發執行了打印任務。

package com.xw.executosmultithreaddemo;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        testnewCachedThreadPool();
    }

    private void testnewCachedThreadPool(){
    
        //創建可緩存的線程池,如果線程池的容量超過了任務數,自動回收空閒線程,任務增加時可以自動添加新線程,線程池的容量不限制
        ExecutorService cachedThreadPool = Executors.newCachedThreadPool();

        //提交 4個任務
        cachedThreadPool.execute(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 8; i++) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+" A" + "===" + i);
                }
                System.out.println(Thread.currentThread().getName()+" A" + "任務結束.....");
            }
        });
        cachedThreadPool.execute(new Runnable() {

            @Override
            public void run() {
                for (int i = 0; i < 8; i++) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+" B" + "===" + i);
                }
                System.out.println(Thread.currentThread().getName()+" B" + "任務結束.....");
            }
        });
        cachedThreadPool.execute(new Runnable() {

            @Override
            public void run() {
                for (int i = 0; i < 8; i++) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+" C" + "===" + i);
                }
                System.out.println(Thread.currentThread().getName()+" C" + "任務結束.....");
            }
        });
        cachedThreadPool.execute(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 8; i++) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+" D" + "===" + i);
                }
                System.out.println(Thread.currentThread().getName()+" D" + "任務結束.....");
            }
        });

        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        cachedThreadPool.execute(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 8; i++) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+" E"+ "===" + i);
                }
                System.out.println(Thread.currentThread().getName()+" E" + "任務結束.....");
            }
        });


    }
}

打印結果可以看出,創建的線程數與第一次創建提交的任務數相等(4個),而5秒後再次創建提交一個任務,也是可以立即被執行的。所以線程數量隨任務數可以伸縮增加。

com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===0
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-2 B===0
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-3 C===0
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-4 D===0

com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===1
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-2 B===1
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-4 D===1
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-3 C===1

com.xw.executosmultithreaddemo I/System.out: pool-2-thread-2 B===2
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-4 D===2
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===2
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-3 C===2

com.xw.executosmultithreaddemo I/System.out: pool-2-thread-4 D===3
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-2 B===3
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===3
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-3 C===3

com.xw.executosmultithreaddemo I/System.out: pool-2-thread-4 D===4
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-2 B===4
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===4
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-3 C===4
//第五個線程開啓 開始工作了
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-5 E===0

com.xw.executosmultithreaddemo I/System.out: pool-2-thread-4 D===5
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-3 C===5
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===5
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-2 B===5

com.xw.executosmultithreaddemo I/System.out: pool-2-thread-4 D===6
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-5 E===1
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===6
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-2 B===6
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-3 C===6

com.xw.executosmultithreaddemo I/System.out: pool-2-thread-4 D===7
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-2 B===7
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-3 C===7
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-5 E===2
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===7

com.xw.executosmultithreaddemo I/System.out: pool-2-thread-4 D任務結束.....
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A任務結束.....
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-3 C任務結束.....
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-2 B任務結束.....

com.xw.executosmultithreaddemo I/System.out: pool-2-thread-5 E===3
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-5 E===4
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-5 E===5
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-5 E===6
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-5 E===7
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-5 E任務結束.....

3. newScheduledThreadPool,創建定長線程池,可執行週期性的任務。

注意通過newScheduledThreadPool對象調用scheduleWithFixedDelay()與execute()方法的區別:

① 使用scheduleWithFixedDelay()每次執行完任務A後,延遲3s後再次週而復始的執行任務A;

② 使用execute()方法,任務B只會被執行一次,結束後,不會再執行任務B。

package com.xw.executosmultithreaddemo;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        testScheduledThreadPool();
    }


    private void testScheduledThreadPool(){
        
        //創建定長線程池,可執行週期性的任務。注意scheduleWithFixedDelay()與execute()方法的區別
        ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3);

        //提交 2個任務
        scheduledThreadPool.scheduleWithFixedDelay(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 8; i++) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+" A" + "===" + i);
                }
                System.out.println(Thread.currentThread().getName()+" A" + "任務結束.....");
            }
        },0,3, TimeUnit.SECONDS);

        scheduledThreadPool.execute(new Runnable() {

            @Override
            public void run() {
                for (int i = 0; i < 8; i++) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+" B" + "===" + i);
                }
                System.out.println(Thread.currentThread().getName()+" B" + "任務結束.....");
            }
        });

    }
}

打印結果:

com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===0
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-2 B===0
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===1
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-2 B===1
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===2
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-2 B===2
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===3
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-2 B===3
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===4
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-2 B===4
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===5
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-2 B===5
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===6
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-2 B===6
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===7
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A任務結束.....
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-2 B===7
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-2 B任務結束.....
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-2 A===0
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-2 A===1
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-2 A===2
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-2 A===3
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-2 A===4
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-2 A===5
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-2 A===6
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-2 A===7
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-2 A任務結束.....
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===0
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===1
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===2
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===3
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===4
 I/System.out: Failed parserXml +java.io.FileNotFoundException: data/bbkc
 I/System.out: Failed parserXml +java.io.FileNotFoundException: data/bbkc
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===5
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===6
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===7
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A任務結束.....
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===0
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===1
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===2
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===3
.....
//呈週期性執行線程 pool-2-thread-1 A

上面的例子我們只提交了2個任務,小於線程池裏能用的線程數量3。思考一個問題,當我們提交的任務大於線程池可用的線程數量時,肯定有一個線程需要排隊等候可用線程的釋放,然後獲取使用。那麼是可週而復始的線程先獲取這個剛剛釋放的線程來用,還是在等待執行的任務先獲得呢?

com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===0
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-2 B===0
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-3 C===0
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===1
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-3 C===1
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-2 B===1
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===2
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-2 B===2
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-3 C===2
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===3
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-3 C===3
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-2 B===3
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===4
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-3 C===4
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-2 B===4
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===5
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-3 C===5
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-2 B===5
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===6
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-3 C===6
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-2 B===6

com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===7
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A任務結束.....
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-3 C===7
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-3 C任務結束.....
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-2 B===7
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-2 B任務結束.....
//所有線程都被釋放了 正在排隊的任務D獲取了第一個線程:pool-2-thread-1 D
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 D===0

com.xw.executosmultithreaddemo I/System.out: pool-2-thread-3 A===0
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 D===1
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-3 A===1
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 D===2
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-3 A===2
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 D===3
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-3 A===3
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 D===4
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-3 A===4
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 D===5
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 D===6
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-3 A===5
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 D===7
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 D任務結束.....
//A週而復始的執行
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-3 A===6
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-3 A===7
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-3 A任務結束.....
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-2 A===0
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-2 A===1
......

上面的註釋已經回答了。是在排隊的任務D先獲取線程。 而scheduleWithFixedDelay(),第二個參數指的是意思下次執行該任務時,需要延遲幾秒,該參數不能爲0,否則程序會崩潰。

4. newSingleThreadExecutor,創建單線程的線程池,線程異常結束,會創建一個新的線程,能確保任務按提交順序執行。

package com.xw.executosmultithreaddemo;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        testSingleThreadPool();
    }

    private void testSingleThreadPool(){

        //單線程的線程池,線程異常結束,會創建一個新的線程,能確保任務按提交順序執行
        ExecutorService singleThreadPool = Executors.newSingleThreadExecutor();

        //提交 4個任務
        singleThreadPool.execute(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 5; i++) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+" A" + "===" + i);
                }
                System.out.println(Thread.currentThread().getName()+" A" + "任務結束.....");
            }
        });

        singleThreadPool.execute(new Runnable() {

            @Override
            public void run() {
                for (int i = 0; i < 5; i++) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+" B" + "===" + i);
                }
                System.out.println(Thread.currentThread().getName()+" B" + "任務結束.....");
            }
        });

        singleThreadPool.execute(new Runnable() {

            @Override
            public void run() {
                for (int i = 0; i < 5; i++) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+" C" + "===" + i);
                }
                System.out.println(Thread.currentThread().getName()+" C" + "任務結束.....");
            }
        });

        singleThreadPool.execute(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 5; i++) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+" D" + "===" + i);
                }
                System.out.println(Thread.currentThread().getName()+" D" + "任務結束.....");
            }
        });

    }
}

打印結果可以看出,即使任務出現了異常,線程池還是會自動補充一個線程繼續執行下面的任務

com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===0
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===1
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===2
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===3
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===4
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A任務結束.....
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 B===0
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 B===1
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 B===2
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 B===3
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 B===4
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 B任務結束.....
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 C===0
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 C===1
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 C===2
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 C===3
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 C===4
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 C任務結束.....
 I/System.out: Failed parserXml +java.io.FileNotFoundException: data/bbkcore
 I/System.out: Failed parserXml +java.io.FileNotFoundException: data/bbkcore
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 D===0
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 D===1
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 D===2
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 D===3
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 D===4
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 D任務結束.....
I/System.out: e:java.lang.ClassNotFoundException: com.mediatek.cta.CtaHttp
I/System.out: [OkHttp] sendRequest>>
I/System.out: [OkHttp] sendRequest<<
I/System.out: e:java.lang.ClassNotFoundException: com.mediatek.cta.CtaHttp
I/System.out: [OkHttp] sendRequest>>
//所有任務執行完,不會再重複執行

5. newSingleThreadScheduledExecutor,創建單線程可執行週期性任務的線程池。

scheduleWithFixedDelay 固定的延遲時間執行任務; scheduleAtFixedRate 固定的頻率執行任務

package com.xw.executosmultithreaddemo;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        testSingleScheduledThreadPool();
    }

    private void testSingleScheduledThreadPool(){
        //創建工作線程數爲 3 的線程池,每當提交一個任務就創建一個線程,直到達到線程池的最大數量,這時線程數量不再變化,當線程發生錯誤結束時,線程池會補充一個新的線程
        //ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);

        //創建可緩存的線程池,如果線程池的容量超過了任務數,自動回收空閒線程,任務增加時可以自動添加新線程,線程池的容量不限制
        //ExecutorService cachedThreadPool = Executors.newCachedThreadPool();

        //創建定長線程池,可執行週期性的任務
        //ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3);

        //單線程的線程池,線程異常結束,會創建一個新的線程,能確保任務按提交順序執行
        //ExecutorService singleThreadPool = Executors.newSingleThreadExecutor();

        //創建單線程可執行週期性任務的線程池
        ScheduledExecutorService singleScheduledThreadPool = Executors.newSingleThreadScheduledExecutor();

        //提交 3個任務
        singleScheduledThreadPool.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 5; i++) {

                    System.out.println(Thread.currentThread().getName()+" A" + "===" + i);
                }
                System.out.println(Thread.currentThread().getName()+" A" + "任務結束.....");
            }
        },0,3,TimeUnit.SECONDS);

        singleScheduledThreadPool.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 5; i++) {

                    System.out.println(Thread.currentThread().getName()+" B" + "===" + i);
                }
                System.out.println(Thread.currentThread().getName()+" B" + "任務結束.....");
            }
        },0,3,TimeUnit.SECONDS);

        singleScheduledThreadPool.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 5; i++) {

                    System.out.println(Thread.currentThread().getName()+" C" + "===" + i);
                }
                System.out.println(Thread.currentThread().getName()+" C" + "任務結束.....");
            }
        },0,3,TimeUnit.SECONDS);
    }
}

可以看出,三個任務統一延遲3秒後,再重複執行一輪任務,週而復始,若每個任務延遲時間不一致,則延遲夠時間後繼續執行。

com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===0
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===1
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===2
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===3
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===4
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A任務結束.....
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 C===0
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 C===1
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 C===2
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 C===3
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 C===4
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 C任務結束.....
//停頓3秒後,重複執行一輪任務
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===0
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===1
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===2
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===3
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===4
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A任務結束.....
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 B===0
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 B===1
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 B===2
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 B===3
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 B===4
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 B任務結束.....
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 C===0
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 C===1
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 C===2
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 C===3
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 C===4
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 C任務結束.....
//停頓3秒後,重複執行一輪任務
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===0
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===1
com.xw.executosmultithreaddemo I/System.out: pool-2-thread-1 A===2
....

6. newWorkStealingPool,創建任務可竊取線程池,空閒線程可以竊取其他任務隊列的任務,不保證執行順序,適合任務耗時差異較大。

Creates a thread pool that maintains enough threads to support the given parallelism level, and may use multiple queues to reduce contention. The parallelism level corresponds to the maximum number of threads actively engaged in, or available to engage in, task processing. The actual number of threads may grow and shrink dynamically. A work-stealing pool makes no guarantees about the order in which submitted tasks are executed.

創建一個線程池,該線程池維護足夠的線程來支持給定的並行級別,並可以使用多個隊列來減少爭用。並行性級別對應於活動參與或可用參與任務處理的最大線程數。線程的實際數量可以動態地增加或減少。工作竊取池不能保證提交任務的執行順序。

package com.xw.executosmultithreaddemo;

import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;

import android.os.Build;
import android.os.Bundle;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class MainActivity extends AppCompatActivity {

    @RequiresApi(api = Build.VERSION_CODES.N)
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        testWorkStealingThreadPool();
    }

    @RequiresApi(api = Build.VERSION_CODES.N)
    private void testWorkStealingThreadPool(){
        
        //創建3個工作線程的 任務可竊取線程池,如果不設置並行數,默認取 CPU 總核數
        ExecutorService workStealingThreadPool = Executors.newWorkStealingPool(3);
        //提交 4個任務
        workStealingThreadPool.execute(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 2; i++) {
                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+" A" + "===" + i);
                }
                System.out.println(Thread.currentThread().getName()+" A" + "此任務執行0.4秒,任務結束.....");
            }
        });

        workStealingThreadPool.execute(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 3; i++) {
                    try {
                        Thread.sleep(300);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+" B" + "===" + i);
                }
                System.out.println(Thread.currentThread().getName()+" B" + "此任務執行0.9秒,任務結束.....");
            }
        });

        workStealingThreadPool.execute(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 8; i++) {
                    try {
                        Thread.sleep(300);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+" C" + "===" + i);
                }
                System.out.println(Thread.currentThread().getName()+" C" + "此任務執行2.4秒,任務結束.....");
            }
        });

        workStealingThreadPool.execute(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 5; i++) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+" D" + "===" + i);
                }
                System.out.println(Thread.currentThread().getName()+"D" + "此任務執行5秒,任務結束.....");
            }
        });
    }
}

空閒線程可以竊取其他任務隊列的任務,不保證執行順序

I/System.out: ForkJoinPool-1-worker-1 A===0
I/System.out: ForkJoinPool-1-worker-2 B===0
I/System.out: ForkJoinPool-1-worker-3 C===0
I/System.out: ForkJoinPool-1-worker-1 A===1
I/System.out: ForkJoinPool-1-worker-1 A此任務執行0.4秒,任務結束.....
I/System.out: ForkJoinPool-1-worker-2 B===1
I/System.out: ForkJoinPool-1-worker-3 C===1
m.xw.executosmultithreaddemo I/System.out: ForkJoinPool-1-worker-2 B===2
m.xw.executosmultithreaddemo I/System.out: ForkJoinPool-1-worker-3 C===2
m.xw.executosmultithreaddemo I/System.out: ForkJoinPool-1-worker-2 B此任務執行0.9秒,任務結束.....
m.xw.executosmultithreaddemo I/System.out: ForkJoinPool-1-worker-3 C===3
m.xw.executosmultithreaddemo I/System.out: ForkJoinPool-1-worker-1 D===0
m.xw.executosmultithreaddemo I/System.out: ForkJoinPool-1-worker-3 C===4
m.xw.executosmultithreaddemo I/System.out: ForkJoinPool-1-worker-3 C===5
m.xw.executosmultithreaddemo I/System.out: ForkJoinPool-1-worker-3 C===6
m.xw.executosmultithreaddemo I/System.out: ForkJoinPool-1-worker-1 D===1
m.xw.executosmultithreaddemo I/System.out: ForkJoinPool-1-worker-3 C===7
m.xw.executosmultithreaddemo I/System.out: ForkJoinPool-1-worker-3 C此任務執行2.4秒,任務結束.....
m.xw.executosmultithreaddemo I/System.out: ForkJoinPool-1-worker-1 D===2
m.xw.executosmultithreaddemo I/System.out: ForkJoinPool-1-worker-1 D===3
m.xw.executosmultithreaddemo I/System.out: ForkJoinPool-1-worker-1 D===4
m.xw.executosmultithreaddemo I/System.out: ForkJoinPool-1-worker-1D此任務執行5秒,任務結束.....

關於第六個創建線程池的方式,沒有模擬出來。但它的用法沒什麼問題。可以再去搜索其他的文章看看newWorkStealingPool()是什麼輸出效果!

關於線程池的使用基本上就是這些了!總結,共勉!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章