实现线程池

1.线程池是什么?

线程池,字面意思来说,有点类似与我们的字符串常量池,数据库连接池等等。

1.1 为啥要引入线程池这一概念呢??

🍃这得从引入线程说起,,

🍃进程本身已经能做到 并发编程了,为啥还要有线程??进程太重量了,创建和销毁成本都比较高(需要申请、释放资源),而线程就是针对上述问题的优化(同一个进程中的线程共用同一组系统资源)

🍃虽然如此,但是在更频繁的创建、释放资源的场景下,线程也有点扛不住了!!

所以,进一步优化,就引入了线程池。线程池存在的目的,就是为了让程序猿不必创建新的线程,直接使用已有的线程完成想要进行的工作即可!!

🍁【线程池解决问题的思路】

把线程创建好了之后,放到池子里,需要使用线程,就直接从池子里取,而不是通过系统来创建。当线程用完了,又放回池子里,而不是通过系统来销毁!!

1.2 为什么把线程放到池子里,从池子里取线程就要比从系统这里创建线程效率高呢??

🍃1.从池子里取,是纯用户态操作。

🍃2.通过系统来创建,涉及到内核操作。

而我们通常认为,牵扯到内核态操作,就要比纯用户态的操作更低效!!结合下图场景理解

 


 2.标准库中的线程池

🍃1.使用 Executors.newFixedThreadPool(10) 能创建出固定包含 10 个线程的线程池.

🍃2.返回值类型为 ExecutorService
🍃3.通过 ExecutorService.submit 可以注册一个任务到线程池中 .
public static void main(String[] args) {
    ExecutorService threadPool = Executors.newFixedThreadPool(10);
    for(int i = 0; i < 100; i++) {
        threadPool.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println("hello");
            }
        });
    }
}

注意这行代码:

ExecutorService threadPool = Executors.newFixedThreadPool(10);

newFixedThreadPool Executors 类的一个静态方法,像这种借助静态方法创建实例,这样的方法,称为"工厂方法",对应的设计模式,就叫做"工厂模式"。

通常情况下,创建对象,是借助 new ,调用构造方法来实现的。但是 Java 里面的构造方法,有诸多限制,在很多时候不方便使用,因此就需要给构造方法再包装一层,外层起到包装作用的方法就是工厂方法!!

🍃为什么构造方法有时候不方便使用??

构造方法的限制在于,当前构造方法的名字务必是和类名一样。要想实现不同版本的构造,就得通过重载,但是重载又要求参数类型和个数不同。当我们的场景刚好是参数类型相同且参数个数相同的时候,重载就行不通了!!请看以下例子:

当我需要用构造方表示两个点:一个是笛卡尔坐标系,构造点;一个是极坐标系构造点。

class Point {
    // 笛卡尔坐标系,构造点
    public Point(double x, double y) { };
    // 使用极坐标系,构造点
    public Point(double r, double a) { };

    // Error : 编译错误
}

显然,这段代码编译错误,不符合重载规则,这时候我们就需要使用工厂模式来解决上述问题了。

class Point {
    // 笛卡尔坐标系,构造点
    public static Point makePointByXY(double x, double y) {
        Point point = new Point();
        point.setX(x);
        point.setY(y);
        return point;
    }
    // 极坐标系,构造点
    public static Point makePointByRA(double r, double a) {
        Point point = new Point();
        point.setR(r);
        point.setA(a);
        return point;
    }
}

于是此时实例化只需要通过类名调用需要的静态方法即可创建!!

🍁Executors 创建线程池的几种方式:

🍃1.newFixedThreadPool: 创建固定线程数的线程池
🍃2.newCachedThreadPool: 创建线程数目动态增长的线程池 .
🍃3.newSingleThreadExecutor: 创建只包含单个线程的线程池 .
🍃4.newScheduledThreadPool: 设定 延迟时间后执行命令,或者定期执行命令 . 是进阶版的 Timer.

 Executors 里面的各种工厂方法,其实都是针对 ThreadPoolExecutor 这个类进行了 new 并且闯入不同风格的参数,来达到构造不同种类线程池的目标!!


3.实现线程池

class MyThreadPool {
    // 这个队列就是 "任务队列" 把当前线程要完成的任务都放入到这个队列中
    // 再由线程池内部的工作线程负责完成它们!!
    private BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>();

    // 核心方法,往线程池里插入任务
    public void submit(Runnable runnable) {
        try {
            queue.put(runnable);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    // n : 设定线程池里有几个线程
    public MyThreadPool(int n) {
        // 构造方法中就需要创建一些线程,让这些线程负责执行上述插入的任务
        for(int i = 0; i < n; i++) {
            Thread t = new Thread(() -> {
                while(!Thread.currentThread().isInterrupted()) {
                    try {
                        // 取出任务,直接执行
                        Runnable runnable = queue.take();
                        runnable.run();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
            t.start();
        }
    }
}
public class TestDemo3 {
    public static void main(String[] args) {
        // 10 个线程一起执行 100 个任务
        MyThreadPool myThreadPool = new MyThreadPool(10);
        for(int i = 0; i < 100; i++) {
            myThreadPool.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println("hello");
                }
            });
        }
    }
}

线程池的实现相比于定时器,要简单太多了!! 

🍁【基本步骤】

🍃1.核心操作为 submit,将任务加入线程池中;

🍃2.使用一个 BlockingQueue 组织所有的任务;

🍃3.每个线程,不停的从 BlockingQueue 中取任务并执行即可。


本篇博客就到这里了,谢谢观看!!

  • 5
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Master_hl

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值