一、创建线程的三种方式
Java语言中是用Thread类来表示线程,线程的创建和开启都是通过Thread类来实现的。
继承Thread类重写run方法。
调用线程对象的start()方法启动线程(启动后还是执行run方法的),而不是调用创建的子类对象的run()方法。
可以使用匿名内部类创建Runnable接口的线程
具体这三种线程的创建可以看idea中的代码,已经都敲过了
二、3种创建线程方式的对比
三、线程Thread类的常用API
四、线程的安全问题
多个线程同时操作同一个共享资源的时候可能会出现业务安全问题,称为线程安全问题(对共享资源进行增删改操作)。
五、线程池的创建、使用、参数
5.1线程池的作用
线程池的作用:线程池就是一个可以复用线程的技术。
例如:不使用线程池的情况下,10个请求我就要创建10个线程,并且使用完后还要销毁这些线程。使用线程池后,我只创建3个线程,再这3个线程处理完当前线程后,就会处理任务队列中剩下的线程,并且核心线程是不会被销毁的,会一直存在。(这里3个线程是随便写的,不是具体算出来的)。
线程过多会占用CPU、内存等资源,所以使用线程池后,会缓解这些现象的发生。
5.2 线程池的7个参数
5.3创建线程池的方式
2、使用ThreadPoolExecutor创建线程池(阿里规范中只能使用这个)
ArrayBlockingQueue<>(5):任务队列数量为5
LinkedBlockingQueue<>():任务队列数量无穷,可以存放无数个任务。
2、使用Executors工具类创建线程池。
5.4 线程池的执行流程
语言描述: 某某公司分部(threadFactory)为客户办理业务,一共有4个柜员(maximumPoolSize),不忙的时段就分配2个柜员(corePoolSize)办理业务,剩余2人休息。摆了4个椅子(workQueue),供客户进行等待。并且这个公司给员工定了个规定,就是当工作区的柜员都在工作,并且等待区的座位都做满时,那么处于休息区的柜员要出来帮忙。直到所有柜员都在工作,等待区也坐满了。那为了我们公司员工身体的考虑,暂时拒绝任何人来办理业务(handler),如果有某个员工空闲下来并且超过了10(keepAliveTime)分钟(unit),那就可以回到休息区休息,但是必须保证有2个柜员在工作区。
5.5 线程池的拒绝策略
5.5 线程池处理Runnable任务
线程池处理Runnable任务是使用execute方法。ThreadPoolExecutor中的execute方法:
- 线程池会创建线程并调用线程中的run方法
- execute方法中需要的参数是Runnable接口的实现类
- 这种方法和submit方法最大的区别是没有返回值
创建Runnable接口的实现类MyRunnable,具体的代码如下:
其中Thread.sleep(Integer.MAX_VALUE),是为了让线程一直执行,这样就不会执行完之后去执行后面的线程。
创建一个线程池,核心线程数为3,最大线程数为5,队列中可存放的线程数量为2。
使用execute方法创建3个线程任务:
此时会创建3个线程。
使用execute方法创建5个线程任务:
核心线程数为3,所以还是创建3个线程。剩下的2个线程任务放入任务队列中。
使用execute方法创建7个线程任务:
核心线程数为3,所以还是创建3个线程。2个线程任务放入任务队列中。剩下的2个线程任务由创建的2个临时线程执行。
使用execute方法创建8个线程任务:
核心线程数为3,所以还是创建3个线程。2个线程任务放入任务队列中。剩下的2个线程任务由创建的2个临时线程执行。最后的一个线程任务会直接触发拒绝策略。
上面演示execute方法创建线程的过程正好验证了5.4中线程池的执行流程。
5.6 线程池处理Callable任务
线程池处理Callable任务是使用submit方法。ThreadPoolExecutor中的submit方法:
- 返回值类型为Future
- 通过get方法获得具体的返回值
六、进程和线程的关系
进程是程序的一个执行实例,是正在执行的程序。一个进程可以包括多个线程。下面展示的就是多个进程,每个进程里面又包含多个线程。例如开启一个百度网盘,百度网盘这个进程中就可以包括下载线程和传输线程等。
七、物理CPU、核心数、逻辑处理器之间的关系
首先,需要知道的是:
1、物理CPU数就是主板上实际插入的CPU数量。
2、CPU的核心数是指物理上,也就是硬件上存在着几个核心。比如,双核就是包括2个相对独立的CPU核心单元组,四核就包含4个相对独立的CPU核心单元组。
3、总核数 = 物理CPU个数 × 每颗物理CPU的核数
4、总逻辑CPU数(总逻辑处理器数) = 物理CPU个数 × 每颗物理CPU的核数 × 超线程数
7.1、查看物理CPU的个数
在cmd命令中输入“systeminfo”,以下信息表示物理CPU只有1个。
7.2、查看CPU核心数、线程数
在cmd命令中输入“wmic”,然后在出现的新窗口中输入“cpu get *”。
NumberOfCores:表示CPU核心数
NumberOfLogicalProcessors:表示CPU线程数
这里的CPU线程数和任务管理器中CPU的逻辑处理器是一样的,表示在某个瞬间CPU能同时并行处理的任务数。
对应任务管理器中的CPU的内核数和逻辑处理器
逻辑处理器表示CPU能同时处理线程的个数,所以CPU能同时处理20个线程。
上面的结果表明CPU是14核20线程的,说明CPU包含14个相对独立的CPU核心单元组,能在某一时刻同时处理20个线程。
为什么是20个线程而不是28个线程呢?
i5 13600K采用的是混合架构,大小核设计,由6个性能核+8个能效核混合架构组成导致的,其中性能核支持超线程,而能效核转不支持超线程。性能核通过超线程技术,1个核心可以对应两个线程,也就是说它可以同时运行两个线程,所以6个性能核对应12个线程,最终12+8得出来20个线程,而不是28个线程。
参考地址:
Windows下查看电脑的CPU个数,核心数,线程数_如何查看电脑核心数-CSDN博客
https://www.cnblogs.com/fetty/p/8580583.html
八、 并发、并行的概念
并发:CPU会轮询为系统的每个线程服务,由于CPU切换的速度很快,给我们感觉这些线程在同时执行,这就是并发。
这些线程并不是同时执行,而是由于CPU的切换速度很快,给人感觉像是在同时执行。例如之前介绍的CPU是14核20线程,
这个CPU最多能同时执行20个线程,CPU就会轮询的执行例如前20个线程,再执行后面的20个线程,再执行前面20个线程,给人感觉这40个线程像是在同一时刻执行。
并行:在同一个时刻上,同时有多个线程在被CPU处理并执行。这里指的是实际被同时执行的线程,例如之前介绍的CPU是14核20线程,这个CPU最多能同时执行20个线程,所以在同一时刻,最多同时有20个线程被CPU处理并执行。
总结:
并发:CPU分时轮询的执行线程。
并行:同一个时刻同时在执行。