线程池四种使用方式的实现及详细介绍(必看):

说明:本文对线程池的四种使用方式分别进行了实现,每种方式的详细介绍及关键点在代码的备注中

建议学习之前先参考:深入理解线程和线程池(图文详解)一文

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.*;

public class Main {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //线程池的四种使用方式(说明及关键点在实现方法中):
        //方式一:
        newCachedThreadPool();
        //方式二:
//        fixdThreadPool(5);
        //方式三:
//        newScheduledThreadPool(6);
        //方式四
//        newSingleThreadExecutor();
    }

    //方式一:newCachedThreadPool
    //      可缓存的线程池,该线程池中“没有核心线程,非核心线程的数量为无限大”,(核心线程在没用时候也不回收)
    //      就是说当有需要时创建线程来执行任务,没有需要时“回收”线程,适用于耗时少,任务量大的情况。
    //注意:线程池为无限大,当执行第二个任务时第一个任务已经完成,会复用执行第一个任务的线程,而不用每次新建线程。
    //      加上//****处那段代码就是体现此特点
    private static void newCachedThreadPool() throws ExecutionException, InterruptedException {
        ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
        for (int i = 0; i < 20; i++) {//线程池中线程数可以有无限大个
//            //****  线程先睡一秒,再执行。由于睡一秒的过程前面线程已经执行完毕,所以不用开启新的线程,直接复用前面线程即可。
//                        所以才会重复用第一个线程
//            final int index = i;
//            try {
//                Thread.sleep(index * 1000);
//            }
//            catch (InterruptedException e) {
//                e.printStackTrace();
//            }
            //执行线程的方法1:调用runnableh中的run方法,此方法不向客户端返回执行结果
            cachedThreadPool.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println("执行线程:" + Thread.currentThread().getName());
                }
            });
        }
    }

    //方式二:fixdThreadPool
    //      定长的线程池,“有核心线程,核心线程的即为最大的线程数量,没有非核心线程”
    //      创建一个定长线程池,超出的线程会在队列中等待,即使线程空闲也不会回收。
    //注意:1.此处线程池传入创建的线程有5个,但是有十个任务等待执行,先FIFO的顺序执行前五个线程,后五个在队列中等待。
    //        前五个线程执行完毕后再按照FIFO的顺序执行。
    //      2.定长线程池的大小最好根据系统资源进行设置。如Runtime.getRuntime().availableProcessors()。可参考PreloadDataCache。
    private static void fixdThreadPool(int size) throws ExecutionException, InterruptedException {
        ExecutorService executorService = Executors.newFixedThreadPool(size);
        for (int i = 0; i < 10; i++) {
            //3.此处算法在线程执行直线进行睡眠,但是不会像newCatchThreadPool中那样重复在执行线程1,
            //  因为这里线程直接是创建了固定大小的,直接用(不用也不会回收)
            final int index = i;
            try {
                Thread.sleep(index * 1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //执行线程的方法2:调用Callable中的call方法,此方法可以向客户端返回执行结果
            Future<Integer> task = executorService.submit(new Callable<Integer>() {
                @Override
                public Integer call() throws Exception {
                    System.out.println("执行线程:" + Thread.currentThread().getName());
                    return null;
                }
            });
            System.out.println("第" + i + "次计算,结果:" + task.get());
        }
    }

    //方式三:newScheduledThreadPool,创建一个定长的线程池,支持定时及周期性任务执行
    private static void newScheduledThreadPool(int size) {
        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(size);
        Date d = new Date();
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println(df.format(d));
        //法一:schedule()延迟一定时间后执行任务
        //参数1:为执行的任务;参数2:任务的延迟间隔;参数3:为延迟执行的时间单位:
            scheduledExecutorService.schedule(new Runnable() {
                @Override
                public void run() {
                    Date d = new Date();
                    SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    System.out.println(df.format(d));
                    System.out.println("执行线程:" + Thread.currentThread().getName());
                }
            }, 10, TimeUnit.SECONDS); //表示线程延迟十秒执行,任务只执行一次

        //法二:scheduleAtFixedRate(...):按指定频率周期执行某个任务。如12:00执行第一次,15:00执行第二次,18:00执行第三次...
        //(个人认为与法三的区别是:每个任务的开始时间是以一定周期开始的,后面任务开始时可能前面任务还未完成。
        // 而法三则是在前面任务完成的时间点上延迟一定时间执行)
        // 参数1:为执行的任务;参数2:初始任务延迟时间;参数3:执行的周期;参数4:为延迟执行的时间单位:
//        scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
//            @Override
//            public void run() {
//                Date d = new Date();
//                SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//                System.out.println(df.format(d));
//                System.out.println("执行线程:"+Thread.currentThread().getName());
//            }
//        },2,3,TimeUnit.SECONDS);//初始化延迟2s开始执行,每隔3s重新执行一次任务。
        //上面如果当前时间是10点,设置initialDelay:2,period:3,unit:小时
        //第一次:10:00 + 2 = 12:00
        //第二次:10:00 + 2 + 3 =15:00
        //第三次:10:00 + 2 + 2*3 =18:00
        //第n次:10:00 + 2 + n*3...

        //法三:scheduleWithFixedDelay(...):按指定频率间隔执行某个任务
        // 参数1:为执行的任务;参数2:为初始延迟时间;参数3:后续任务的延迟执行时间;参数4:为延迟执行的时间单位:
        // 解释:
        //      第一次调度开始时间点=当前时间+initialDelay
        //      下一次调度开始时间点=上一次task完成时间点+delay
//        scheduledExecutorService.scheduleWithFixedDelay(new Runnable() {
//            @Override
//            public void run() {
//                Date d = new Date();
//                SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//                System.out.println(df.format(d));
//                System.out.println("执行线程:"+Thread.currentThread().getName());
//            }
//        },5,3,TimeUnit.SECONDS);//初始化延迟5s开始执行,后续任务开始时间是在其前一个任务结束后延迟2s重新执行。
    }

    //方式四:newSingleThreadExecutor:创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,
    //       保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行
    private static void newSingleThreadExecutor() {
        ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
        for (int i = 0; i < 10; i++) {
            final int index=i;
            singleThreadExecutor.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        System.out.println("任务:"+index);
                        System.out.println("执行线程:"+Thread.currentThread().getName());
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            });
        }
    }
}

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值