Java Web 实战 10 - 多线程基础之线程池

大家好 , 这篇文章给大家带来的是多线程当中的线程池 , 使用线程池可以降低资源消耗 , 通过重复利用已创建的线程降低线程创建和销毁造成的消耗 . 还可以提高响应速度 , 当任务到达时,任务可以不需要等到线程创建就能立即执行
我们会从三个角度分析线程池

  1. 线程池是什么
  2. 标准库中的线程池
  3. 我们自己实现一个线程池

推荐大家跳转到此链接查看文章体验效果更好嗷~
上一篇文章的链接我也给大家贴在这里了
在这里插入图片描述

8.4 线程池

对于 “池” 这个字 , 我们学习过 : “字符串常量池” “数据库连接池” “备胎池”

“备胎池” : 养了许多的备胎 , 这个分了那个就无缝连接 , 提高了效率

进程已经能做到并发编程了 , 为什么还需要线程 ?
进程实在是太重量了 , 创建和销毁成本都比较高 , 需要申请释放资源
线程就是针对上述问题的优化 , 因为他是共用同一组系统资源的 , 一旦资源申请好了 , 后续就不需要再继续申请了

虽然线程已经很好了 , 不过在更高频率下的创建释放的情况下 , 线程也就扛不住了
所以还需要进一步优化 :

  1. 线程池
  2. 协程 (也叫做纤程) , 更加轻量级的线程

我们主要研究一下线程池 :
线程池解决的思路就是把线程创建好之后 , 放到池子中 , 而不是通过系统来销毁
当线程用完了 , 还是还回到池子中 , 而不是通过系统来进行销毁
上述操作 , 就又进一步的提高效率了

❗ 那为什么把线程放到池子里 , 然后从池子中取出线程就要比从系统中创建线程来得快呢 ?
✅ 从池子中取 , 是纯用户态操作 . 通过系统来创建 , 涉及到内核态操作
通常认为 , 牵扯到内核态的操作1 , 就是要比纯用户态的操作更低效

为什么说用户态操作比内核态操作更高效呢 ?
举个栗子 :
image.png

扫描二维码关注公众号,回复: 14603905 查看本文章

1. 标准库中的线程池

image.png
刚才是创建的固定个数的线程池
我们还可以创建线程数量动态增加的线程池

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Demo24 {
    
    
    public static void main(String[] args) {
    
    
        // ExecutorService 叫做执行器服务
        // Executors.newFixedThreadPool() 创建固定线程个数的线程池
        // Executors 是静态方法
        // Executors通过.的方式调用静态方法

        // 固定个数的线程池
        ExecutorService threadPool = Executors.newFixedThreadPool(10);

        // 线程数量动态增加的线程池
        // Executors.newCachedThreadPool();
        
        
    }
}

学习完怎样创建之后 , 我们接下来就可以使用线程池了

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Demo24 {
    
    
    public static void main(String[] args) {
    
    
        // ExecutorService 叫做执行器服务
        // Executors.newFixedThreadPool() 创建固定线程个数的线程池
        // Executors 是静态方法
        // Executors 通过.的方式调用静态方法

        // 固定个数的线程池
        ExecutorService threadPool = Executors.newFixedThreadPool(10);

        // 线程数量动态增加的线程池
        // Executors.newCachedThreadPool();

        // 把任务加入到线程池中
        // 与定时器类似,线程池内部也有线程阻止退出,我们需要手动关闭
        threadPool.submit(new Runnable() {
    
    
            @Override
            public void run() {
    
    
                System.out.println("hello 线程池");
            }
        });
    }
}

2. 自己实现简单的线程池

阻塞队列来保存一些任务 , submit 方法给线程池添加任务 , 线程池内部再持有一些线程来消费执行这里的任务
线程池就相当于一个简单的生产者-消费者模型

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

class MyThreadPool {
    
    
    // 由于插入任务可以一次性插入很多.需要能够把当前尚未执行的任务都保存起来 -> 队列
    // 这个队列就是一个任务队列,把当前线程池中要完成的内容都放到这个队列里
    // 再由线程池内部的工作线程负责完成他们
    private BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>();

    // 核心方法:往线程池中插入任务
    public void submit(Runnable runnable) {
    
    
        try {
    
    
            queue.put(runnable);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
    }

    // 构造方法中,就需要创建一些线程,让这些线程负责完成上述执行任务的工作
    public MyThreadPool(int n) {
    
    
        for (int i = 0; i < n; i++) {
    
    
            Thread t = new Thread(() -> {
    
    
                // 直接写成 true 就写死了,也别让他一直循环
                // 我们可以改成 !Thread.currentThread().isInterrupted()
                // 作用
                // 1. 判断标志位
                // 2. 处理异常
                while(!Thread.currentThread().isInterrupted()) {
    
    
                    try {
    
    
                        Runnable runnable = queue.take();
                        runnable.run();
                    } catch (InterruptedException e) {
    
    
                        e.printStackTrace();
                        break;// 直接处理
                    }
                }
            });
            t.start();
        }
    }
}

public class Demo25 {
    
    
    public static void main(String[] args) {
    
    
        MyThreadPool myThreadPool = new MyThreadPool(10);
        for (int i = 0; i < 100; i++) {
    
    
            myThreadPool.submit(new Runnable() {
    
    
                @Override
                public void run() {
    
    
                    System.out.println("hello");
                }
            });
        }
    }
}

到这里 , 多线程基础部分就已经结束了
如果对你有帮助的话 , 请一键三连嗷~
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/m0_53117341/article/details/129506329