zoukankan      html  css  js  c++  java
  • 并发编程(三)线程池

    一、线程池的分类

      线程池的创建都是通过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();
                }
            }
        }
    
    }

    运行结果:

    参考资料:

  • 相关阅读:
    Java反射机制(创建Class对象的三种方式)
    webservice原理及基于cxf开发的基本流程
    开始打开eclipse .exe时候显示找不到jre路径
    Token验证详解
    RPC远程协议之Thrift入门
    RPC远程协议之原理分析
    Jmeter进行性能测试时多台负载机的配置方法
    Jmeter分布式部署测试-----远程连接多台电脑做压力性能测试
    Java 集合系列05之 LinkedList详细介绍(源码解析)和使用示例
    理解Cookie和Session机制
  • 原文地址:https://www.cnblogs.com/riches/p/11947659.html
Copyright © 2011-2022 走看看