线程池:神秘的“轻量级线程”

当前我们的多线程部分已经学习了几个代码案例:

1.单例模式

2.阻塞队列 -> 生产者消费者模型

3.定时器

4.线程池

而线程存在的意义就是,使用进程来实现并发编程会“太重了”,创建和销毁进程都会比较耗资源。

但是线程会更加高效。此时,使用多线程就可以在很多时候代替进程来实现并发编程了。

但是随着并发程度的提高,随着我们对于性能要求的标准的提高,咱们发现,好像线程也没有那么轻量。

当我们需要频繁创建销毁线程的时候,就发现好像开销还是挺大的~

想要进一步的再提高这里的效率,想出了两种办法:

1.搞一个“轻量级进程” (协程/纤程)(但还没有被加入到Java标准库中)

2.使用线程池(字符串常量池、数据库连接池),来降低创建/销毁线程的开销。

也就是说,现在有一个可以存放线程的池子,事先把需要使用的线程创建好,后面需要使用的时候,直接从池子里去出出来。如果用完了也还给池。(因为这两个动作比创建/销毁更加高效)

创建/销毁线程,是交由操作系统内核完成的,但是从池子里获取/还给池,是咱们自己用户代码就能实现的,不必交给内核操作~

相比于内核来说,用户态,程序执行的行为是可控的,如果要想做某个工作,就会非常干净利落的完成(比如从池子里取、还给池子)

但是如果是通过内核,此时不清楚内核身上背负着多少个任务,无法确定内核都要做哪些工作,整体过程是不可控的~

ExecutorService pool = Executors.newFixedThreadPool(10);

线程池:神秘的“轻量级线程”_第1张图片

工厂模式:简单的来说,就是用普通的方法,来代替构造方法创建对象~

此处就是构造出一个10个线程的线程池,然后就可以随时安排这些线程帮我们干活了~

线程池提供了一个重要的方法:submit,可以给线程池提交若干个任务

public class testdemo {
    public static void main(String[] args) {

        ExecutorService pool = Executors.newFixedThreadPool(10);

        for(int i = 0 ; i < 1000 ; i++){
            int n = i;
            pool.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println("hello" + n);
                }
            });
        }
    }
}      运行程序后发现,main线程结束了,但是整个线程没结束,
       线程池中的线程都是前台线程,此时会组织进程结束~

这段代码中,往线程池放了1000个任务,1000任务就是由这10个线程来平均分配一下,然后再执行打印,差不多是一个线程执行100个(注意这里并非是严格的平均,可能有的多一个,有的少一个)

每个线程都执行完一个打印的任务后,再执行下一个任务,由于每个任务执行时间都差不多,因此 每个线程做的任务数量就差不多~

进一步的可以认为:这1000个任务,就在一个队列中排队,这10个线程,就依次来取队列中的任务,取一个就执行一个执行完了再执行下一个~

问题就来了:

这么简单的代码中,为什么不直接打印的时候打印 i 呢?而是通过 int n = i 这样的操作来完成~

这其中涉及到变量捕获。

线程池:神秘的“轻量级线程”_第2张图片

 

Executors提供的工厂类

线程池:神秘的“轻量级线程”_第3张图片

线程池:神秘的“轻量级线程”_第4张图片

 还有一个包需要我们注意一下:

java.util.concurrent   这个包里放的很多类都是和并发编程(多线程编程密切相关的) 所以这个包也叫做juc

corePoolSize :          核心线程数

maximumPoolSize:最大线程数

ThreadPoolExecutor相当于把里面的线程分为两类:

一类是核心线程(理解为正式员工),一类是临时工(实习生),这俩之和是最大线程数~

同时允许正式员工摸鱼,不允许实习生摸鱼~如果实习生摸鱼太久了,就会被销毁(开除)。

整体的策略,就是正式员工保底,临时工动态调节。

long keepAliveTime: 描述了临时工摸鱼的最大时间

TimeUnit unit : 时间单位(s,ms,分钟)

BlockingQueue workQueue:线程池的任务队列

ThreadFactory threadFactory : 用于创建线程,线程池是需要创建线程的

RejictedExecutionHandler hander : 描述了线程池的“拒绝策略”

线程池:神秘的“轻量级线程”_第5张图片

实际开发的时候,线程池的线程数,设定成多少合适呢?

并没有具体的数字,要具体情况具体分析,不能说是1.5N、2N(N是cpu的核心数)等等~

你可能感兴趣的:(java,开发语言)