Java并发(二)——线程相关类与线程池

来源:互联网 发布:西部数码 域名 编辑:程序博客网 时间:2024/05/21 22:54

第六部分 线程相关类

6.1 继承关系

Executor接口-<--ExecutorService接口<--AbstractExecutorService抽象类<--ThreadPoolExecutor类

6.2 Executor接口

6.2.1 接口声明

public interface Executor

6.2.2 接口概述

Executor是一个顶层接口,在它里面只声明了一个方法execute(Runnable),返回值为void,参数为Runnable类型,从字面意思可以理解,就是用来执行传进去的任务的

6.3 ExecutorService接口

6.3.1 接口声明

public interface ExecutorService extends Executor

6.3.2 接口概述

ExecutorService接口继承了Executor接口,并声明了一些方法:submit、invokeAll、invokeAny以及shutDown等

6.3.3 方法概述

(1)void shutdown()

关闭线程池,执行以前提交的任务,但不接受新任务。如果已经关闭,则调用没有其他作用。

(2)List shutdownNow()

试图停止所有正在执行的活动任务,暂停处理正在等待的任务,并返回等待执行的任务列表。无法保证能够停止正在处理的活动执行任务,但是会尽力尝试。

(3)boolean isShutdown()
如果此执行程序已关闭,则返回 true。

(4)boolean isTerminated()
如果关闭后所有任务都已完成,则返回 true。注意,除非首先调用 shutdown 或 shutdownNow,否则 isTerminated 永不为 true。

(5)<T> Future<T> submit(Callable<T> task)
提交一个Callable任务用于执行,返回一个表示任务等待完成的Future。该 Future 的 get 方法在成功完成时将会返回该任务的结果。如果想立即阻塞任务的等待,则可以使用 result = exec.submit(aCallable).get(); 形式的构造。

(6)<T> Future<T> submit(Runnable task, T result)
提交一个 Runnable 任务用于执行,并返回一个表示该任务的 Future。该 Future 的 get 方法在成功完成时将会返回给定的结果。result - 返回的结果

(7)Future<?> submit(Runnable task)
提交一个 Runnable 任务用于执行,并返回一个表示该任务的 Future。该 Future 的 get 方法在成功完成时将会返回 null。

6.4 AbstractExecutorService类

6.4.1 类的声明

public abstract class AbstractExecutorService extends Object implements ExecutorService

6.4.2 类的概述

提供ExecutorService执行方法的默认实现

6.5 ThreadPoolExecutor类

6.5.1 类的定义

public class ThreadPoolExecutor extends AbstractExecutorService

6.5.2 类的概述

  为了便于跨大量上下文使用,此类提供了很多可调整的参数和扩展钩子 (hook)。但是,强烈建议程序员使用较为方便的 Executors 工厂方法 Executors.newCachedThreadPool()Executors.newFixedThreadPool(int)Executors.newSingleThreadExecutor(),它们均为大多数使用场景预定义了设置。否则,在手动配置和调整此类时,使用以下指导:
(1)核心和最大池大小
ThreadPoolExecutor 将根据 corePoolSize和maximumPoolSize设置的边界自动调整池大小。

1) 当新任务在方法 execute(java.lang.Runnable) 中提交时,如果运行的线程少于corePoolSize,则创建新线程来处理请求,即使其他辅助线程是空闲的;
2) 如果运行的线程多于 corePoolSize 而少于 maximumPoolSize,则仅当队列满时才创建新线程;
3) 如果设置的 corePoolSize 和 maximumPoolSize 相同,则创建了固定大小的线程池;
4) 如果将 maximumPoolSize 设置为基本的无界值(如 Integer.MAX_VALUE),则允许池适应任意数量的并发任务。
在大多数情况下,核心和最大池大小仅基于构造来设置,不过也可以使用 setCorePoolSize(int) 和 setMaximumPoolSize(int) 进行动态更改。

(2)按需构造
默认情况下,即使核心线程最初只是在新任务到达时才创建和启动的,也可以使用方法 prestartCoreThread() 或 prestartAllCoreThreads() 对其进行动态重写。如果构造带有非空队列的池,则可能希望预先启动线程。

(3)创建新线程
使用 ThreadFactory 创建新线程。如果没有另外说明,则在同一个 ThreadGroup 中一律使用 Executors.defaultThreadFactory() 创建线程,并且这些线程具有相同的 NORM_PRIORITY 优先级和非守护进程状态。

(4)保持活动时间
如果池中当前有多于corePoolSize 的线程,则这些多出的线程在空闲时间超过 keepAliveTime 时将会终止。这提供了当池处于非活动状态时减少资源消耗的方法。如果池后来变得更为活动,则可以创建新的线程。

(5)排队
所有 BlockingQueue 都可用于传输和保持提交的任务。可以使用此队列与池大小进行交互:如果运行的线程少于 corePoolSize,则 Executor 始终首选添加新的线程,而不进行排队;如果运行的线程等于或多于 corePoolSize,则 Executor 始终首选将请求加入队列,而不添加新的线程;如果无法将请求加入队列,则创建新的线程,除非创建此线程超出 maximumPoolSize,在这种情况下,任务将被拒绝。

(6)被拒绝的任务
当 Executor 已经关闭,或者Executor 将有限边界用于最大线程和工作队列容量,且已经饱和时,在方法 execute(java.lang.Runnable) 中提交的新任务将被拒绝。

(7)钩子 (hook) 方法
此类提供 protected 可重写的 beforeExecute(java.lang.Thread, java.lang.Runnable) 和 afterExecute(java.lang.Runnable, java.lang.Throwable) 方法,这两种方法分别在执行每个任务之前和之后调用。它们可用于操纵执行环境;例如,重新初始化 ThreadLocal、搜集统计信息或添加日志条目。

6.5.3 方法概述

// 构造方法
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue)

用给定的初始参数和默认的线程工厂及被拒绝的执行处理程序创建新的 ThreadPoolExecutor。workQueue - 执行前用于保持任务的队列。此队列仅保持由 execute 方法提交的 Runnable 任务。

public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory)

用给定的初始参数和默认被拒绝的执行处理程序创建新的 ThreadPoolExecutor。threadFactory - 执行程序创建新线程时使用的工厂。

// 一般方法
(1)public void execute(Runnable command)

在将来某个时间执行给定任务。可以在新线程中或者在现有池线程中执行该任务。如果无法将任务提交执行,或者因为此执行程序已关闭,或者因为已达到其容量,则该任务由当前 RejectedExecutionHandler 处理。

(2)public void shutdown()

按过去执行已提交任务的顺序发起一个有序的关闭,但是不接受新任务。如果已经关闭,则调用没有其他作用。

(3)public List<Runnable> shutdownNow()

尝试停止所有的活动执行任务、暂停等待任务的处理,并返回等待执行的任务列表。

(4)public void setThreadFactory(ThreadFactory threadFactory)

设置用于创建新线程的线程工厂。

(5)public ThreadFactory getThreadFactory()

返回用于创建新线程的线程工厂。

(6)public void setCorePoolSize(int corePoolSize)

设置核心线程数。此操作将重写构造方法中设置的任何值。如果新值小于当前值,则多余的现有线程将在下一次空闲时终止。如果较大,则在需要时启动新线程来执行这些排队的任务。

(7)public void setMaximumPoolSize(int maximumPoolSize)
设置允许的最大线程数。此操作将重写构造方法中设置的任何值。如果新值小于当前值,则多余的现有线程将在下一次空闲时终止。

6.6 Executors类

6.6.1 类的定义

public class Executors extends Object

6.6.2 类的概述

此包中所定义的 Executor、ExecutorService、ScheduledExecutorService、ThreadFactory 和 Callable 类的工厂和实用方法。

6.6.3 方法概述

// 静态方法
(1)public static ExecutorService newFixedThreadPool(int nThreads)

创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程。如果在所有线程处于活动状态时提交附加任务,则在有可用线程之前,附加任务将在队列中等待。如果在关闭前的执行期间由于失败而导致任何线程终止,那么一个新线程将代替它执行后续的任务(如果需要)。

(2)public static ExecutorService newSingleThreadExecutor()

创建一个使用单个 worker 线程的 Executor,以无界队列方式来运行该线程。可保证顺序地执行各个任务,并且在任意给定的时间不会有多个线程是活动的。

与其他等效的 newFixedThreadPool(1) 不同,可保证无需重新配置此方法所返回的执行程序即可使用其他的线程。

(3)public static ExecutorService newCachedThreadPool()

创建一个可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用它们。如果现有线程没有可用的,则创建一个新线程并添加到池中;终止并从缓存中移除那些已有 60 秒钟未被使用的线程。因此,长时间保持空闲的线程池不会使用任何资源。

(4)public static ScheduledExecutorService newSingleThreadScheduledExecutor()

创建一个单线程执行程序,它可安排在给定延迟后运行命令或者定期地执行。可保证顺序地执行各个任务,并且在任意给定的时间不会有多个线程是活动的。与其他等效的 newScheduledThreadPool(1) 不同,可保证无需重新配置此方法所返回的执行程序即可使用其他的线程

(5)public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)

创建一个线程池,它可安排在给定延迟后运行命令或者定期地执行

6.6.4 通用线程池的实现

(1)固定大小线程池

public static ExecutorService newFixedThreadPool(int nThreads) {    return new ThreadPoolExecutor(nThreads, nThreads,                                  0L, TimeUnit.MILLISECONDS,                                  new LinkedBlockingQueue<Runnable>());}

(2)单一线程池

public static ExecutorService newSingleThreadExecutor() {    return new FinalizableDelegatedExecutorService        (new ThreadPoolExecutor(1, 1,                                0L, TimeUnit.MILLISECONDS,                                new LinkedBlockingQueue<Runnable>()));}

(3)可变大小线程池

public static ExecutorService newCachedThreadPool() {    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,                                  60L, TimeUnit.SECONDS,                                  new SynchronousQueue<Runnable>());}

6.7 线程池使用示例

6.7.1 ThreadPoolExecutor使用示例

import java.util.concurrent.ThreadPoolExecutor;import java.util.concurrent.ArrayBlockingQueue;import java.util.concurrent.TimeUnit;public class Test {     public static void main(String[] args) {            ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 200, TimeUnit.MILLISECONDS,                 new ArrayBlockingQueue<Runnable>(5));// coreSize=5, maxSize=10, keeplive=200, 指定队列类型及长度         for(int i=0;i<15;i++){             MyTask myTask = new MyTask(i);             executor.execute(myTask);// 任务放入线程池             System.out.println("线程池中线程数目:"+executor.getPoolSize()+",队列中等待执行的任务数目:"+                     executor.getQueue().size()+",已执行完别的任务数目:"+executor.getCompletedTaskCount());             // 每30ms添加一个任务             try {                Thread.sleep(30L);            } catch (InterruptedException e) {                // TODO Auto-generated catch block                e.printStackTrace();            }         }         executor.shutdown();// 关闭线程池         // 每40ms显示一下线程池状态         while (!executor.isTerminated()) {             System.out.println("线程池中线程数目:"+executor.getPoolSize()+",队列中等待执行的任务数目:"+                     executor.getQueue().size()+",已执行完别的任务数目:"+executor.getCompletedTaskCount());             try {                Thread.sleep(40L);            } catch (InterruptedException e) {                e.printStackTrace();            }         }     }}class MyTask implements Runnable {    private int taskNum;    public MyTask(int num) {        this.taskNum = num;    }    @Override    public void run() {        // 每个任务执行500ms        try {            Thread.currentThread().sleep(500L);        } catch (InterruptedException e) {            e.printStackTrace();        }//        System.out.println(taskNum);    }}

这里写图片描述

6.7.2 newSingleThreadExecutor

import java.util.concurrent.ExecutorService;  import java.util.concurrent.Executors;public class SingleThreadExecutorTest {      public static void main(String[] args) {          ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();          // 依次添加任务        for (int i = 0; i < 10; i++) {            final int index = i;            singleThreadExecutor.execute(new Runnable() {                public void run() {                    try {                        System.out.println(index);                        Thread.sleep(200L);                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }            });        }        singleThreadExecutor.shutdown();// 关闭线程池    }}

这里写图片描述

6.7.3 newFixedThreadPool

import java.util.concurrent.ExecutorService;  import java.util.concurrent.Executors;public class FixedThreadPoolTest {      public static void main(String[] args) {          ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);          // 依次添加任务        for (int i = 0; i < 10; i++) {            final int index = i;            fixedThreadPool.execute(new Runnable() {                public void run() {                    System.out.println(index+"进入线程池 <<");                    try {                        Thread.sleep(200L);                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                    System.out.println(index+"退出线程池>>");                }            });        }        fixedThreadPool.shutdown();// 关闭线程池    }}

这里写图片描述

6.7.4 newCachedThreadPool

import java.util.concurrent.ExecutorService;  import java.util.concurrent.Executors;public class CachedThreadPoolTest {      public static void main(String[] args) {          ExecutorService cachedThreadPool = Executors.newCachedThreadPool();          // 依次添加任务        for (int i = 0; i < 10; i++) {            final int index = i;            cachedThreadPool.execute(new Runnable() {                public void run() {                    System.out.println(index+"进入线程池 <<");                    try {                        Thread.sleep(200L);                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                    System.out.println(index+"退出线程池>>");                }            });        }        cachedThreadPool.shutdown();// 关闭线程池    }}

这里写图片描述

6.7.5 newScheduledThreadPool

import java.util.concurrent.Executors;import java.util.concurrent.ScheduledExecutorService;public class ScheduledThreadPoolTest {    public static void main(String[] args) {        // 不要用ExecutorService实现类型多态,不然无法访问子类特有的方法        ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(1);// 核心池大小为1        for (int i = 0; i < 1; i++) {            final int num = i;            Runnable task = new Runnable() {                @Override                public void run() {                    System.out.println(num+"开始执行《《"+System.currentTimeMillis());                    try {                        Thread.sleep(100L);                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                    System.out.println(num+"执行结束>>");                }            };             // 添加任务            System.out.println(System.currentTimeMillis());            scheduledThreadPool.schedule(task, 300, java.util.concurrent.TimeUnit.MILLISECONDS);// 延时300ms后执行该任务        }        scheduledThreadPool.shutdown();    }}

这里写图片描述

1 0