Java最新Java多线程(六):线程池详解,mybatis的缓存面试题

总结

以上是字节二面的一些问题,面完之后其实挺后悔的,没有提前把各个知识点都复习到位。现在重新好好复习手上的面试大全资料(含JAVA、MySQL、算法、Redis、JVM、架构、中间件、RabbitMQ、设计模式、Spring等),现在起闭关修炼半个月,争取早日上岸!!!

下面给大家分享下我的面试大全资料

  • 第一份是我的后端JAVA面试大全

image.png

后端JAVA面试大全

  • 第二份是MySQL+Redis学习笔记+算法+JVM+JAVA核心知识整理

字节二面拜倒在“数据库”脚下,闭关修炼半个月,我还有机会吗?

MySQL+Redis学习笔记算法+JVM+JAVA核心知识整理

  • 第三份是Spring全家桶资料

字节二面拜倒在“数据库”脚下,闭关修炼半个月,我还有机会吗?

MySQL+Redis学习笔记算法+JVM+JAVA核心知识整理

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

可以看到,使用 submit() 可以执行带有返回值的任务或者无返回值的任务,而 execut() 只能执行不带返回值的任务。

3.2.4 线程工厂

作用:为线程池提供现成的创建。

提供的功能

  1. 设置线程池中线程的命名规则;

  2. 设置线程优先级;

  3. 设置线程分组;

  4. 设置线程类型(守护线程 || 用户线程)。

示例代码


public class ThreadPoolDemo3 {

    public static void main(String[] args) {

        // 1.创建线程工厂

        ThreadFactory factory = r -> {

            // 一定要把任务 Runnable 设置给新线程

            Thread thread = new Thread(r);

            // 设置线程的命名规则

            thread.setName("我的线程:" + r.hashCode());

            // 设置线程的优先级

            thread.setPriority(Thread.MAX_PRIORITY);

            return thread;

        };

        ExecutorService service = Executors.newFixedThreadPool(5, factory);

        for (int i = 0; i < 5; i++) {

            service.submit(() -> {

                // 任务

                Thread thread = Thread.currentThread();

                System.out.println("线程池开始执行:" + thread.getName() + "线程池优先级:" + thread.getPriority());

            });

        }

    }

}

运行结果

f5f73caaa109477fbb5186130114c8ac.png

3.2 带缓存的线程池(Executors.newCachedThreadPool)


线程池会根据任务数创建线程,并且在一定时间内可以重复使用这些线程。

示例代码


public class ThreadPoolDemo4 {

    public static void main(String[] args) {

        // 创建线程池

        ExecutorService service = Executors.newCachedThreadPool();

        for (int i = 0; i < 1000; i++) {

            int finalI = i;

            service.submit(() -> System.out.println("i:" + finalI + " 线程名称:" + Thread.currentThread().getName()));

        }

    }

}

运行结果

46ec94f8e0684a9fb0e4dc50f984b317.png

该方式适用于短时间有且有大量任务的场景,它的缺点是可能占用很多资源。

3.3 执行定时任务(Executors.newSingleThreadExecutor)


3.3.1 延迟执行(1次)

示例代码


public class ThreadPoolDemo12 {

    public static void main(String[] args) {

        ScheduledExecutorService threadPool =

                Executors.newScheduledThreadPool(10);

        // 定时任务

        System.out.println("设置定时任务:" + new Date());

        // 延迟 n 秒后执⾏(只执⾏⼀次)

        threadPool.schedule(() -> System.out.println("schedule:" + new Date()), 2, TimeUnit.SECONDS);

    }

}

执行结果

24d99ba8b075450c9b6fbf7c3de1208f.png

延迟 2s 后执行一次。

3.3.2 固定频率执行( scheduleAtFixedRate)

示例代码


public class ThreadPoolDemo13 {

    public static void main(String[] args) {

        ScheduledExecutorService threadPool =

                Executors.newScheduledThreadPool(10);

        // 定时任务

        System.out.println("设置定时任务:" + new Date());

        threadPool.scheduleAtFixedRate(() -> 

                System.out.println("scheduleAtFixedRate:" + new Date()), 3, 2, TimeUnit.SECONDS);

    }

}

运行结果

d02c62b4d17244a99833d62de95ad1c3.png

延迟3s后执行,之后每2s执行一次。

参数解释

  1. 参数1:执行任务;

  2. 参数2:延迟 n 秒后执行;

  3. 参数3:执行定时任务的频率;

  4. 参数4:配合参数3使用的时间单位。

3.3.3 scheduleAtFixedRate VS scheduleWithFixedDelay

scheduleAtFixedRate 是以上⼀次任务的开始时间,作为下次定时任务的参考时间的(参考时间+延迟任务=任务执行)。

示例代码


public class ThreadPoolDemo5 {

    public static void main(String[] args) {

        // 创建线程池

        ScheduledExecutorService service = Executors.newScheduledThreadPool(5);

        System.out.println("添加任务执行时间:" + LocalDateTime.now());



        // 2s之后开始执行定时任务,定时任务每隔4s执行一次

        service.scheduleAtFixedRate(() -> {

            System.out.println("执行了任务:" + LocalDateTime.now());

            try {

                Thread.sleep(5 * 1000);

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

        }, 2, 4, TimeUnit.SECONDS);

    }

}

运行结果

d2eaa030a21045d8abb210f898cc803c.png

2s后开始执行定时任务,每隔5s执行一次。

设置的是每隔4秒执行一次定时任务,为什么实际上是5s执行一次呢?

6c048b2483f6b0a991f2625df7ba443a.jpg

注意,如果执行任务时间大于设置的定时任务执行时间,那么此方法会以执行任务的时间为准,简而言之,就是哪个时间长就以哪个时间作为定时任务执行的周期。

scheduleWithFixedDelay 是以上⼀次任务的结束时间,作为下次定时任务的参考时间的。

示例代码


public class ThreadPoolDemo5 {

    public static void main(String[] args) {

        // 创建线程池

        ScheduledExecutorService service = Executors.newScheduledThreadPool(5);

        System.out.println("添加任务执行时间:" + LocalDateTime.now());



        // 2s之后开始执行定时任务,每次执行间隔4秒

        service.scheduleWithFixedDelay(() -> {

            System.out.println("执行了任务:" + LocalDateTime.now());

            try {

                Thread.sleep(5 * 1000);

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

        }, 2, 4, TimeUnit.SECONDS);

    }

}

运行结果

31ee960d3f3f401a9898399ad76aa684.png

2s后开始执行任务,每隔9秒执行一次定时任务。

为什么这个也不是每隔4s执行一次,而是9s呢???

a9682dd3d74f6e825d0520c181230ffe.jpg

因为  scheduleWithFixedDelay 是以上⼀次任务的结束时间,作为下次定时任务的参考时间的,上个任务执行5s后,再延时4s执行延时任务。

3.4 定时任务单线程(Executors.newSingleThreadScheduledExecutor)


示例代码


public class ThreadPoolDemo6 {

    public static void main(String[] args) {

        ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();

        System.out.println("添加任务时间:" + LocalDateTime.now());

        service.schedule(() -> System.out.println("执行任务:" + LocalDateTime.now()), 2, TimeUnit.SECONDS);

    }

}

运行结果

acd4cb63045e48f9a81563e624f37dba.png

3.5 单线程线程池(Executors.newSingleThreadExecutor)


示例代码


public class ThreadPoolDemo7 {

    public static void main(String[] args) {

        ExecutorService service = Executors.newSingleThreadExecutor();

        for (int i = 0; i < 10; i++) {

            int finalI = i;

            service.submit(() -> System.out.println("任务:" + finalI + ", 线程名:" + Thread.currentThread().getName()));

        }

    }

}

运行结果

23cf3518d934489eba24f34b44b655a5.png

单线程的线程池有什么意义呢?

  1. 自定义拒绝策略;

  2. 提供了任务队列和任务管理的功能。

3.6 根据当前CPU生成线程池(Executors.newWorkStealingPool)


示例代码


public class ThreadPoolDemo8 {

    public static void main(String[] args) {

        ExecutorService service = Executors.newWorkStealingPool();

        for (int i = 0; i < 100; i++) {

            service.submit(() -> System.out.println("线程名:" + Thread.currentThread().getName()));

        }

        while (!service.isTerminated()){

        }

    }

}

运行结果

3282d33482c2420a841adc8ce2913961.png

3.7 手动方式(ThreadPoolExecutor)


3.7.1 创建忽略最新任务的线程池

示例代码


public class ThreadPoolDemo11 {

    public static void main(String[] args) {

        ThreadFactory factory = r -> {

            Thread thread = new Thread(r);

            return thread;

        };



        // 手动方式创建线程池

        ThreadPoolExecutor executor =

                new ThreadPoolExecutor(2, 2, 10, TimeUnit.SECONDS,

                        new LinkedBlockingDeque<>(2), factory, new ThreadPoolExecutor.DiscardPolicy());

        for (int i = 0; i < 5; i++) {

            int finalI = i;

            executor.submit(() -> {

                try {

                    Thread.sleep(finalI * 100);

                } catch (InterruptedException e) {

                    e.printStackTrace();

                }

                System.out.println(Thread.currentThread().getName() + "执行任务" + finalI);

            });

        }

        // 终止线程池

        executor.shutdown();

    }

}

运行结果

5e02e5d8fdb9479e8540bef1dfbaf048.png

3.7.2 ThreadPoolExecutor 参数说明

  1. corePoolSize:核心线程数,可以大致理解为长期驻留的线程数目(除非设置了allowCoreThreadTimeOut)。对于不同的线程池,这个值可能会有很大区别,比如newFixedThreadPool 会将其设置为 nThreads,而对于 newCachedThreadPool 则是为 0。

  2. maximumPoolSize:顾名思义,就是线程不够时能够创建的最⼤线程数。同样进⾏对比,对于newFixedThreadPool,当然就是 nThreads,因为其要求是固定大小,而 newCachedThreadPool 则是 Integer.MAX_VALUE。

  3. keepAliveTime:空闲线程的保活时间,如果线程的空闲时间超过这个值,那么将会被关闭。注意此值生效条件必须满足:空闲时间超过这个值,并且线程池中的线程数少于等于核⼼线程数corePoolSize。当然核心线程默认是不会关闭的,除非设置了allowCoreThreadTimeOut(true)那么核心线程也可以被回收。

  4. TimeUnit:时间单位。

  5. BlockingQueue:任务队列,用于存储线程池的待执行任务的。

  6. threadFactory:⽤于生成线程,⼀般我们可以⽤默认的就可以了。

  7. handler:当线程池已经满了,但是又有新的任务提交的时候,该采取什么策略由这个来指定。有几种方式可供选择,像抛出异常、直接拒绝然后返回等,也可以自己实现相应的接口实现自己的逻辑。

3.7.3 线程池执行流程

113ca706d90145e7a0c447a03452a610.png

3.7.4 拒绝策略(5种(4(JDK提供的) + 1(自定义拒绝策略)))

JDK提供的四种拒绝策略:

5376df4b44604ccea59dc230a36a04a2.png

  1. DiscardPolicy : 忽略旧任务(队列第一个任务)

  2. AbortPolicy : 提示异常,拒绝执行(默认的拒绝策略)

  3. CallerRunsPolicy : 使用调用线程池的线程来执行任务

  4. DiscardOldestPolicy :  忽略最新任务

自定义拒绝策略

示例代码


public class ThreadPoolDemo10 {

    public static void main(String[] args) {

        ThreadFactory factory = r -> {

            Thread thread = new Thread(r);

            return thread;

        };



        // 手动方式创建线程池

        ThreadPoolExecutor executor =

                new ThreadPoolExecutor(2, 2, 10, TimeUnit.SECONDS,

                        new LinkedBlockingDeque<>(2), factory,

                        new RejectedExecutionHandler() {

                            @Override

                            public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {

                                // 自定义拒绝策略

                                System.out.println("自定义拒绝策略");

                            }

                        });

        for (int i = 0; i < 5; i++) {

            int finalI = i;

            executor.submit(() -> {

                try {

                    Thread.sleep(finalI * 100);

                } catch (InterruptedException e) {

                    e.printStackTrace();

                }

                System.out.println(Thread.currentThread().getName() + "执行任务" + finalI);

            });

        }

        // 终止线程池

        executor.shutdown();

    }

}

运行结果:

595f02605134493bb8277ddb1d3642a2.png

4. 线程池状态

=========

独家面经总结,超级精彩

本人面试腾讯,阿里,百度等企业总结下来的面试经历,都是真实的,分享给大家!

image

image

image

image

Java面试准备

准确的说这里又分为两部分:

  1. Java刷题
  2. 算法刷题

Java刷题:此份文档详细记录了千道面试题与详解;

image

image

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

}

}




**运行结果:**



 ![595f02605134493bb8277ddb1d3642a2.png](https://img-blog.csdnimg.cn/595f02605134493bb8277ddb1d3642a2.png)



4\. 线程池状态

=========







# 独家面经总结,超级精彩

本人面试腾讯,阿里,百度等企业总结下来的面试经历,都是真实的,分享给大家!

[外链图片转存中...(img-FyFzGSAm-1715377457868)]

[外链图片转存中...(img-LtIgdRNY-1715377457868)]

[外链图片转存中...(img-OZd6Q2PJ-1715377457869)]

[外链图片转存中...(img-PEXfHSao-1715377457870)]

# Java面试准备

准确的说这里又分为两部分:

1.  Java刷题
2.  算法刷题

Java刷题:此份文档详细记录了千道面试题与详解;

[外链图片转存中...(img-AUTSxK2q-1715377457870)]

[外链图片转存中...(img-etZtCzwi-1715377457870)]

> **本文已被[CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】](https://bbs.csdn.net/forums/4f45ff00ff254613a03fab5e56a57acb)收录**

**[需要这份系统化的资料的朋友,可以点击这里获取](https://bbs.csdn.net/forums/4f45ff00ff254613a03fab5e56a57acb)**

  • 22
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值