当前位置:网站首页>多线程进阶篇
多线程进阶篇
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锁的升级策略
偏向锁 ->轻量级锁 ->重量级锁
边栏推荐
- MySQL index
- Finally someone can make the server so straightforward
- [database] transaction
- Feisheng: Based on the Chinese word breaker ik-2 ways to build custom hot word separators Showcase & pit arrangement Showtime
- I have been working as a software testing engineer for 5 years, but I was replaced by an intern. How can I improve myself?
- 飞升:基于中文分词器IK-2种自定义热词分词器构建方式showcase & 排坑showtime
- luoguP2756 飞行员配对方案问题(最大流)
- Title: enter two positive integers m and N to find their maximum common divisor and minimum common multiple
- Shenzhou ares tx6 boot logo modification tutorial
- MySQL事物
猜你喜欢

UE4_ Editor development: highlight the UI making method according to the assets dragged by the mouse (1)

Solidity - 安全 - 重入攻击(Reentrancy)
![[deep learning] data segmentation](/img/16/798881bbee66faa2fb8d9396155010.jpg)
[deep learning] data segmentation

接口中方法详解

Who is promoting the new inflection point of audio and video industry in 2022?

Golang's handwritten Web Framework

Idea of capturing mobile terminal variant combination

STM32F103 series controlled OLED IIC 4-pin

动态规划--怪盗基德的滑翔翼

Basic operations of C language
随机推荐
Golang之手写web框架
CompletionService使用及原理(源码分析)
Finally someone can make the server so straightforward
[exercise] basic practice letter graph of Blue Bridge Cup
Title: enter two positive integers m and N to find their maximum common divisor and minimum common multiple
MySQL數據庫用戶管理
Luogup2756 pilot pairing scheme problem (maximum flow)
MySQL storage system
Switch to software testing and report to the training class for 3 months. It's a high paying job. Is it reliable?
46. 全排列-dfs双百代码
Summary of redis learning notes (I)
English grammar_ Adjective / adverb Level 3 - superlative
动态规划--怪盗基德的滑翔翼
Gestion des utilisateurs de la base de données MySQL
Codeforces C. Andrew and Stones
Voting vault: a new primitive for defi and Governance
Shenzhou ares tx6 boot logo modification tutorial
Projet Web de déploiement du serveur Cloud
How to create a CSR (certificate signing request) file?
Beauty of Refactoring: when multithreaded batch processing task lifts the beam - Universal scaffold