• Java基础入门·多线程·线程池ThreadPool篇


    前言                                                特点分析

    线程池ThreadPool                         销毁线程池

     Executor类                ​​​​​​​        ​​​​​​​        ​​​​​​​    Callable接口

    线程池使用                 ​​​​​​​        ​​​​​​​        ​​​​​​​    Callable启动线程

     ​​​​​​​ExecutorService接口的方法                                               


    前言

    在上一篇Java—实现多线程程序 | 入门的文章中,我们初步了解Thread类的用法

    第一次书写多线程程序,算是完成一个Java学习的里程碑

    接下来我们继续进入多线程的学习

    线程池ThreadPool

    线程池:线程的缓冲池,目的就是提高效率。 new Thread().start(),线程是内存中的一个独立的方法栈区,JVM没有能力开辟内存空间和OS交互

    而线程会频繁地与OS交互浪费资源,线程池就是开辟一个空间,专门用于存储线程对象,可以理解为集合,当线程需要时,就从池子里调用出来,使用结束再丢回线程池,保证了线程不会“死掉”,反复利用,达到高效

    线程池的目的是为了提高线程的利用率,减少创建和销毁线程的开销,降低系统资源的消耗,提高系统的稳定性和可靠性。在高并发的环境中,线程池可以有效地控制并发数量,防止线程因互相竞争而产生死锁、饥饿或者系统资源耗尽等问题。

    tips:后面学到的数据库连接池也是类似的效果

    jdk5开始内置线程池


     Executor类

    使用静态方法创建线程池

    public static newFixedThreadPool(int nThreads)

    创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程。

    int nThreads是传入线程的数量

     方法的返回值是ExecutorService接口的实现类,管理池子里面的线程


    线程池使用 

    创建线程池, 线程数量是两个

    线程数量虽然可以自行定义,但最好不要过多,浪费资源

    ExecutorService es = Executors.newFixedThreadPool(2);

    创建线程对象,线程池管理对象Service,调用方法submit提交线程任务,当然,前提是得先写一个Runnable

    1. public class MyRunnable implements Runnable{
    2. @Override
    3. public void run() {
    4. System.out.println("线程开始运行");
    5. }
    6. }

    ExecutorService接口的方法

    submit(Runnable r)提交线程执行的任务

    1. public class ThreadTest {
    2. public static void main(String[] args) {
    3. ExecutorService es = Executors.newFixedThreadPool(2);
    4. Runnable runnable = new MyRunnable();
    5. es.submit(runnable);
    6. }
    7. }

    特点分析

    这一次运行代码不知道你们是否发现了不同之处 

    以往的代码运行时,程序会自动结束不再运行,而这次你可以看到,程序一直在后台保活,直到我们手动关闭。这就是上文所说线程池的作用:用则拿,不用则还,线程不死

    使用了线程池的程序

    这里的中文乱码比较懒,没有调整,将就着看哈哈,如果你也遇到了中文乱码的问题而没有找到合适的方法,可以看我的另一篇文章,我想它会对你有所帮助⬇⬇⬇解决IntelliJ IDEA 代码运行时中文出现乱码

     同时,为了更直观地看到线程的执行,我们还可以查看一下线程的名字,然后把runnab对象多submit几次

    System.out.println(Thread.currentThread().getName()+"线程开始运行");
    1. public class ThreadTest {
    2. public static void main(String[] args) {
    3. ExecutorService es = Executors.newFixedThreadPool(2);
    4. Runnable runnable = new MyRunnable();
    5. es.submit(runnable);
    6. es.submit(runnable);
    7. es.submit(runnable);
    8. es.submit(runnable);
    9. es.submit(runnable);
    10. }
    11. }
    查看使用中的线程名

    销毁线程池

    当我们不需要使用线程池时,总得让它结束,所以我们就可以把它销毁,自行结束 

    es.shutdown();

     此时我们再运行程序,当所有线程不再使用时,运行到这行代码,线程池就被销毁了


    Callable接口

    Callable也能像Runnable一样建线程,但和Runnable接口有区别

    Callable接口有返回值,且Callablecall方法可以抛出异常(Runnable没有)

     Callable的抽象方法只有一个:call

    我们尝试使用一下相关代码

    1. public class MyCall implements Callable {
    2. public V call() throws Exception {
    3. return null;
    4. }
    5. }

     注意此处的为泛型,即你需要返回数据的类型,此处我们可以改成String,然后return字符串

    1. public class MyCall implements Callable {
    2. public String call() throws Exception {
    3. return "返回字符串";
    4. }
    5. }

    Callable启动线程

    线程调用重写方法call,需要使用到线程池,我们依旧可以使用submit,把submit(Runnable r)改为submit(Callable c)提交线程执行的任务,但当我们运行时没有任何输出结果

    这时候我们就要使用Future接口,Future submit()方法提交线程任务后,方法有个返回值Future接口类型,而它则可以获取到线程执行后返回的结果

    1. public class CallText {
    2. public static void main(String[] args) throws ExecutionException, InterruptedException {
    3. //创建线程池
    4. ExecutorService es = Executors.newFixedThreadPool(2);
    5. //创建线程
    6. MyCall myCall = new MyCall();
    7. //提交线程任务,使用Callable接口实现类
    8. Future future = es.submit(myCall);//返回接口类型Future
    9. //接口的方法get,获取线程的返回值
    10. String str = future.get();
    11. System.out.println("str = "+str);
    12. }
    13. }
    运行结果

  • 相关阅读:
    LeetCode --- 1464. Maximum Product of Two Elements in an Array 解题报告
    视频直播美颜sdk与计算机视觉的奇妙结合
    C++极速掌握,只需这一篇就够了
    【数值计算汇总】js前端数值计算校验转换
    学习和复习mysql这一篇就够了
    python设计模式12:状态模式
    Postman历史版本下载
    学院教学信息管理系统(c++)
    Maven 使用过程中碰到的问题持续集成
    卷积神经网络(李宏毅老师系列)
  • 原文地址:https://blog.csdn.net/neadsc/article/details/132790978