当前位置:网站首页>多线程进阶篇
多线程进阶篇
2022-06-30 06:00:00 【小白的含金量】
目录
线程池
创建线程池的目的
线程池创建的目的在于:如果我们直接采用像之前的Thread构造方法创建线程,其实在每次创建和销毁线程时都有一定的开支,当线程太多时这个开支还是挺明显的。
“池”:目的就是让某些对象被多次重复利用,减少频繁创建和销毁对象带来的开支问题
所以说,线程池最大的好处就是可以减少每次启动和销毁线程的损耗(提高时间和空间利用率)
线程池的概念
线程池内部创建了若干个线程,这些线程都是Runnable的状态,只需要从系统中取出任务(run),就可以立即开始执行。
我们将线程池比作一个餐厅:
餐厅中的固定员工:线程池中的线程
后面招聘的临时员工:当线程池中的线程不够用时,可产生临时员工。
JDK中线程池的使用
线程池的核心父类接口:ExecutorService接口
执行任务方法:excute

提交任务方法:submit
提交一个任务到线程池(线程的run或者call方法),池中会派遣空闲线程执行任务


终止线程方法:shutdown
立即终止所有线程:shutdownNow(); 无论线程是否在空闲状态

停止在空闲态的线程,运行线程在结束后停止:shutdown();
Excutors=>线程池的工具类
这个类可以创建JDK内置的四大线程池
加s的基本都是工具类 比如Arrays(数组工具类,copyOf,sort等等)
固定大小的线程池
//固定大小的线程池
ExecutorService pool = Executors.newFixedThreadPool(10);采用.submit()方法执行任务
pool.submit(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 3; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"绕"+i+"圈");
}
}
});工具类源码:

数量动态变化的缓存池
//数量动态变化的缓存池
ExecutorService pool1 = Executors.newCachedThreadPool();工具类源码:
橘色的参数基本是用不到的,因为最大线程数有四十多亿

单线程池
ps:单线程池的意义在于,省去创建线程和销毁线程的时间,来一个任务执行一个任务,还未执行的任务在工作队列排队执行。
//只包含一个线程的单线程池
ExecutorService pool2 = Executors.newSingleThreadExecutor();工具类源码:

定时线程池
ps:使用的是定时器线程接口,线程池核心接口的子接口
//定时器线程池
ScheduledExecutorService pool3 = Executors.newScheduledThreadPool(10);采用.schedule接收任务,可规定延迟多久执行任务
pool3.schedule(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 3; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"绕"+i+"圈");
}
}
},3, TimeUnit.SECONDS);工具类源码:

线程池的接口和类
ExecutorService:线程池的核心接口,提供excute方法,submit方法,shutdown方法
ScheduledExecutorService:定时器接口,线程池核心接口的子接口,追加.schedule方法,可以延迟启动任务
ThreadPoolExector类:实现核心接口的子类,也是线程池接口的最常用实现子类
Executors:线程池的工具类,提供了ThreadPoolExector的对象,内置创建好的四大线程池。

ThreadPoolExector子类的核心构造方法参数
一图流

线程池工作流程
此工作流程基于submit提交一个新任务时线程池内部的执行流程
首先判断核心池是否已经拉满,没拉满我们可以再创建一个固定线程(正式工)执行此任务
若已经拉满,我们就去判断工作队列是否已满,没有满的话,我们就在队列中排队等待,
否则,进行线程池的最大数量判断,如果没满的话就创建一个空闲线程来执行此任务,
否则,若线程池已经达到了最大数量,说明此时线程池已经达到最大负荷了,我们就需要执行拒绝策略了
开始执行

若已经达到核心池最大数量

若队列已经满了

当线程数量达到上线,执行拒绝策略

常见锁的策略
1.乐观锁和悲观锁
synchronized最开始就是乐观锁,当竞争激烈就变成悲观锁。
乐观锁
每次读写数据都认为不会发生冲突,不会阻塞,一般来说只有在数据更新时才会检查是否发生冲突,若没有冲突直接更新,有冲突再去解决冲突。
当线程冲突不严重时,可以采用乐观锁策略来避免多次的加锁解锁操作
eg:
乐观锁一般通过版本号机制来实现

比如这两个线程,如果线程1先结束并将主内存的版本从version1变成version2时,线程2写回主内存检测到主内存的版本和自己的工作内存版本对不上,就会直接报错,不写回。

当下次再进行线程操作时,就会读取新的版本号,这个时候重新进行操作,尝试写回。

悲观锁:
每次进行读写数据都会冲突,都需要尝试加锁操作,保证同一时间只有一个线程在读写数据。
当线程冲突严重时,就需要加锁,来避免线程频繁访问共享数据失败带来的CPU空转问题
2.读写锁
读写锁的适用条件
特别适用于线程基本都在读数据,很少有些数据的情况。
多数据在访问数据时,并发读数据不会冲突,只有在写数据时才有可能发生冲突,所有就有了读写锁的概念,JDK内置的读写锁是ReentrantReadWriteLock,用这个可实现读写操作。
读写锁的特性
1.多个线程并发读数据时,都可以访问到读锁,并发执行不互斥。
2.多个线程写数据时,两个线程互斥,只有一个能访问到写锁,其他线程阻塞。
3.一个线程读,另一个线程写,也会互斥,当写的过程结束读线程才能继续执行。
3.重量级锁和非重量级锁
重量级锁
需要操作系统和硬件支持,线程获取重量级锁失败进入阻塞状态(os,用户态切换到内核态,开销非常大)
eg:
比如去银行办理业务
用户态:在窗口外自己处理的业务
内核态:窗口内部,需要工作人员协助
这样来回切换是非常耗时的
轻量级锁
尽量在用户态执行操作,线程不阻塞,不会进行状态切换。
轻量级锁的常用实现是采用自旋锁:
之前的方式是,获取锁失败就进入Blocked状态,线程阻塞等待锁释放,然后由CPU唤醒(这个时间一般都比较长,由用户态切换到内核态)。
自旋锁:
就是一个循环的概念
while(获取lock==false)就进行死循环,但不会让出CPU,线程也不会阻塞,不会切换状态,线程就在CPU上空跑,直到锁被释放,就可以很快速地获取到锁。
4.公平锁和非公平锁
公平锁
获取锁失败的线程进入等待队列,当锁被释放,在队列中等待时间最长的线程首先获取到锁。
非公平锁
阻塞队列的各个线程获取到锁的几率相等,不分先后。
synchronized锁的升级策略
偏向锁 ->轻量级锁 ->重量级锁
边栏推荐
- English语法_形容词/副词3级-最高级
- Navigate back to fragmentpageradapter - & gt; Fragment is empty - navigating back to fragmentpageradapter - & gt; fragments are empty
- Official win 10 image download
- Today, Ali came out with 35K. It's really sandpaper that wiped my ass. it showed me my hand
- 股票在网上开户安全吗?在网上能不能开户炒股呢?
- [ansible series] fundamentals -01
- Use of OpenCL thread algebra library viennacl
- Basic operations of C language
- [secretly kill little partner pytorch20 days] - [day4] - [example of time series data modeling process]
- Sword finger offer 29 Print matrix clockwise
猜你喜欢

观察者模式、状态模式在实际工作中的使用

Official win 10 image download

Dao -- a beautiful new world?

VLAN access mode

Configure the user to log in to the device through telnet -- AAA local authentication

Tornado frame foundation

Transfer the token on the matic-erc20 network to the matic polygon

Mysql database learning notes - foreign keys, table connections, subqueries, and indexes for MySQL multi table queries

MySQL index

MySQL transaction
随机推荐
Prototype and prototype chain in JS
Idea of capturing mobile terminal variant combination
Solidy - fallback function - 2 trigger execution modes
CompletableFuture从了解到精通,你想知道的这里都有
Golang之手写web框架
Do you know how to show the health code in only 2 steps
MySQL数据库用户管理
About modifying dual system default startup item settings
Dao -- a beautiful new world?
旋转标注工具roLabelImg
SHELL
24、 I / O device model (serial port / keyboard / disk / printer / bus / interrupt controller /dma and GPU)
MySQL advanced (Advanced SQL statement)
General contents of learning reinforcement learning
[road of system analyst] collection of wrong topics in Project Management Chapter
Vscode configuration proxy
DOM (document object model) document XML file object model
[ansible series] fundamentals -01
How to create a CSR (certificate signing request) file?
Detailed explanation of issues related to SSL certificate renewal