并发编程(三)线程池

一、线程池的分类

  线程池的创建都是通过Executors(创建者接口)这个接口的方法进行创建的,下面我们来了解一下都有哪些线程池:

  • newFixedThreadPool() : 创建一个固定线程线程池
  • newCachedThreadPool() : 创建一个可扩展的线程池。
  • newScheduledThreadPool() : 创建一个可调度(周期执行)的线程池。
  • newSingleThreadExecutor() : 创建一个单线程化(模拟队列)的线程池。

二、线程池实例分析

newFixedThreadPool【固定线程池】

语法:

//创建一个2个线程的线程池
ExecutorService fixedPool = Executors.newFixedThreadPool(2);
  • 最多2个线程将处于活动状态。
  • 如果提交了两个以上的线程,那么它们将保持在队列中,直到线程可用。
  • 如果一个线程由于执行关闭期间的失败而终止,且执行器尚未被调用,则创建一个新线程。
  • 线程会一直存在,直到池关闭。

实例:

/**
 * 固定线程的线程池
 */
public class TestFixedThreadPool {

    public static void main(final String[] arguments) throws InterruptedException {
        //使用Executors(创建者接口创建一个固定两个线程的线程池)
        ExecutorService executor = Executors.newFixedThreadPool(2);

        //ExecutorService接口转换为线程池实例对象
        ThreadPoolExecutor pool = (ThreadPoolExecutor) executor;

        //加入任务前的线程池状态
        System.out.println("线程池大小: " + pool.getCorePoolSize());
        System.out.println("线程池曾经创建过的最大线程数量: " + pool.getLargestPoolSize());
        System.out.println("线程池中允许的最大线程数: " + pool.getMaximumPoolSize());
        System.out.println("线程池中当前线程的数量: " + pool.getPoolSize());
        System.out.println("活动线程数: " + pool.getActiveCount());
        System.out.println("已经分配执行的任务数: " + pool.getTaskCount());

        //线程池中丢进两个线程
        executor.submit(new TestThread());
        executor.submit(new TestThread());

        //加入任务后的线程池状态
        System.out.println("线程池大小: " + pool.getCorePoolSize());
        System.out.println("线程池曾经创建过的最大线程数量: " + pool.getLargestPoolSize());
        System.out.println("线程池中允许的最大线程数: " + pool.getMaximumPoolSize());
        System.out.println("线程池中当前线程的数量: " + pool.getPoolSize());
        System.out.println("活动线程数: " + pool.getActiveCount());
        System.out.println("已经分配执行的任务数: " + pool.getTaskCount());

        //关闭线程池
        executor.shutdown();
    }

    /**
     * 线程实体
     */
    static class TestThread implements Runnable {

        public void run() {
            try {
                Long duration = (long) (Math.random() * 5);//休眠时间,模拟线程内的工作
                System.out.println("运行线程!线程名称为: " + Thread.currentThread().getName());
                TimeUnit.SECONDS.sleep(duration);//休眠
                System.out.println("运行线程完毕!线程名称为: " + Thread.currentThread().getName());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

运行结果:

newCachedThreadPool【可扩展线程池】

语法:

//创建一个可扩展线程池
ExecutorService executor = Executors.newCachedThreadPool();
  • newCachedThreadPool()方法创建一个具有可扩展线程池的执行器。
  • 核心线程数为零
  • 最大线程数为无限
  • 无任务时,线程存活的最大时间为60s
  • 任务队列为同步移交队列,该队列没有缓冲区,即不会有任务会在该队列中排队,每当有任务要入队时,队列都会将任务移交给一个可用的线程

实例:

/**
 * 可扩展线程池
 */
public class TestCachedThreadPool {

    public static void main(final String[] arguments) throws InterruptedException {
        //使用Executors(创建者接口创建一个可扩展线程池)
        ExecutorService executor = Executors.newCachedThreadPool();

        //ExecutorService接口转换为线程池实例对象
        ThreadPoolExecutor pool = (ThreadPoolExecutor) executor;

        //加入任务前的线程池状态
        System.out.println("线程池大小: " + pool.getCorePoolSize());
        System.out.println("线程池曾经创建过的最大线程数量: " + pool.getLargestPoolSize());
        System.out.println("线程池中允许的最大线程数: " + pool.getMaximumPoolSize());
        System.out.println("线程池中当前线程的数量: " + pool.getPoolSize());
        System.out.println("活动线程数: " + pool.getActiveCount());
        System.out.println("已经分配执行的任务数: " + pool.getTaskCount());

        System.out.println("=====开始加入线程=====");
        //线程池中丢进两个线程
        executor.submit(new TestThread());
        executor.submit(new TestThread());
        System.out.println("=====加入线程完毕=====");

        //加入任务后的线程池状态
        System.out.println("线程池大小: " + pool.getCorePoolSize());
        System.out.println("线程池曾经创建过的最大线程数量: " + pool.getLargestPoolSize());
        System.out.println("线程池中允许的最大线程数: " + pool.getMaximumPoolSize());
        System.out.println("线程池中当前线程的数量: " + pool.getPoolSize());
        System.out.println("活动线程数: " + pool.getActiveCount());
        System.out.println("已经分配执行的任务数: " + pool.getTaskCount());

        //关闭线程池
        executor.shutdown();
    }

    /**
     * 线程实体
     */
    static class TestThread implements Runnable {

        public void run() {
            try {
                Long duration = (long) (Math.random() * 5);//休眠时间,模拟线程内的工作
                System.out.println("运行线程!线程名称为: " + Thread.currentThread().getName());
                TimeUnit.SECONDS.sleep(duration);//休眠
                System.out.println("运行线程完毕!线程名称为: " + Thread.currentThread().getName());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

运行结果:

newScheduledThreadPool【可调度(周期执行)线程池】

//创建一个大小为2的可调度(周期执行)的线程池
ExecutorService executor = Executors.newScheduledThreadPool(2);

实例: 

/**
 * 创建一个可调度(周期运行)的线程池。
 * 此线程池支持定时以及周期性执行任务的需求。
 */
public class TestScheduledThreadPool {

    public static void main(String[] args) {
        //使用Executors(创建者接口创建一个可调度的线程池)
        ScheduledExecutorService service = Executors.newScheduledThreadPool(2);


        System.out.println("=====观察周期线程实体(过了周期时间需检测上一个任务,执行完毕后才会接着执行)=====开始");
        scheduleAtFixedRate(service, 1000);//由于执行时间在周期间隔内,每隔5秒会执行一次
        scheduleAtFixedRate(service, 6000);//由于执行时间在周期间隔外,需等上一个任务执行完了以后才能继续执行,所以每隔6秒会执行一次
        System.out.println("=====观察周期线程实体(过了周期时间需检测上一个任务,执行完毕后才会接着执行)=====结束");

        System.out.println("=====观察周期线程实体(从上一个任务结束时间开始计时,过了周期时间立即执行下一个任务)=====开始");
        scheduleWithFixedDelay(service, 1000);//周期为5秒,从任务结束开始计算周期,实际每个任务执行的间隔为5+1=6秒
        scheduleWithFixedDelay(service, 6000);//周期为5秒,从任务结束开始计算周期,实际每个任务执行的间隔为5+6=11秒
        System.out.println("=====观察周期线程实体(从上一个任务结束时间开始计时,过了周期时间立即执行下一个任务)=====开始");


    }

    /**
     * 周期线程实体(过了周期时间需检测上一个任务,执行完毕后才会接着执行)
     * <p>
     * 执行步骤
     * 1、是以上一个任务开始的时间计时
     * 2、period时间过去后,检测上一个任务是否执行完毕,如果上一个任务执行完毕,则当前任务立即执行
     * 3、如果上一个任务没有执行完毕,则需要等上一个任务执行完毕后立即执行
     */
    private static void scheduleAtFixedRate(ScheduledExecutorService service, final int sleepTime) {
        service.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                long start = new Date().getTime();
                System.out.println("scheduleAtFixedRate 开始执行时间:" + DateFormat.getTimeInstance().format(new Date()));
                try {
                    Thread.sleep(sleepTime);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                long end = new Date().getTime();
                System.out.println("scheduleAtFixedRate 执行花费时间=" + (end - start) / 1000 + "m");
                System.out.println("scheduleAtFixedRate 执行完成时间:" + DateFormat.getTimeInstance().format(new Date()));
                System.out.println("======================================");
            }
        }, 1000, 5000, TimeUnit.MILLISECONDS);
    }

    /**
     * 周期线程实体(从上一个任务结束时间开始计时,过了周期时间立即执行下一个任务)
     * <p>
     * 执行步骤
     * 1、是以上一个任务结束的时间计时
     * 2、period时间过去后,立即执行。
     */
    private static void scheduleWithFixedDelay(ScheduledExecutorService service, final int sleepTime) {
        service.scheduleWithFixedDelay(new Runnable() {
            @Override
            public void run() {
                long start = new Date().getTime();
                System.out.println("scheduleWithFixedDelay 开始执行时间:" + DateFormat.getTimeInstance().format(new Date()));
                try {
                    Thread.sleep(sleepTime);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                long end = new Date().getTime();
                System.out.println("scheduleWithFixedDelay执行花费时间=" + (end - start) / 1000 + "m");
                System.out.println("scheduleWithFixedDelay执行完成时间:" + DateFormat.getTimeInstance().format(new Date()));
                System.out.println("======================================");
            }
        }, 1000, 5000, TimeUnit.MILLISECONDS);
    }
}

newSingleThreadExecutor【单线程化(模拟队列)线程池】

语法:

//创建一个单线程化(模拟队列)的线程池
ExecutorService executor = Executors.newSingleThreadExecutor();
  • newSingleThreadExecutor()方法创建一次执行单个任务的执行程序。
  • 此线程池保证所有任务的执行顺序按照任务的提交顺序执行

实例:

/**
 * 单例/线程化线程池【类似模拟一个队列去处理】
 */
public class TestSingleThreadPool {

    public static void main(String[] args) {
        //使用Executors(创建者接口创建一个单例/线程化线程池)
        ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();

        for (int i = 0; i < 10; i++) {
            String threadName = "我是序号为:" + (i + 1) + "的线程";
            singleThreadExecutor.execute(new TestThread(threadName));
        }
        singleThreadExecutor.shutdown();
        System.out.println("main方法执行完毕,线程还在异步运行");

    }

    /**
     * 线程实体
     */
    static class TestThread implements Runnable {
        private String threadName;

        public TestThread(String threadName) {
            this.threadName = threadName;
        }

        public void run() {
            try {
                System.out.println("运行线程!线程名称为: " + threadName);
                TimeUnit.SECONDS.sleep(3);//线程休眠3秒,模拟线程中处理的业务
                System.out.println("运行线程完毕!线程名称为: " + threadName);
                System.out.println("========华丽的分割线========");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

}

运行结果:

参考资料:

原文地址:https://www.cnblogs.com/riches/p/11947659.html