Java并发编程核心的基础知识

目录

一、线程创建(二):Thread类的构造方法、线程运行(二):Thread类的重写run方法

1.Thread的构造方法

Thread作Worker类成员时

2.Thread的重写run方法

Thread作Worker类成员时

(1)从己类Thread出发本层执行run

(2)从己接口Runnable出发下层执行run

(1&2)方法调用

二、锁(四)synchronized&ReentrantLock

1.synchronized

1.1加解锁

synchronized加锁失败:

1.2锁对象

1.3公平性

1.4自协调

2.ReentrantLock

2.1加解锁

2.1.1lock加锁失败:

2.1.2trylock加锁失败:

2.2锁对象

2.3公平性

2.4自协调

三、信号量

1.限制同执线程数

1.1锁

1.2共享锁

2.申请释放资源

2.1acquire

2.2release

四、闭锁CountDownLatch类

[1.new CountDownLatch(int count)](#1.new CountDownLatch(int count))

2.countDown

3.await

五、线程安全(一).5:总&线程安全(二).3:总&修改过期

[1.写写之间 - 线程安全(一).5:总](#1.写写之间 - 线程安全(一).5:总)

1.1起因

1.2原因

1.3现象

1.3.1读取用前过期

①过期旧值

①.1用前过期旧值

①.2用后过期旧值

1.3.2写入片段覆损

[1.4解决 - 串行化](#1.4解决 - 串行化)

[1.4.1防止读取用前过期 => 写块读取的数据 撑得住新](#1.4.1防止读取用前过期 => 写块读取的数据 撑得住新)

[1.4.1.1防用前另使用过期 -> 读串行](#1.4.1.1防用前另使用过期 -> 读串行)

[1.4.1.2防用前另修改过期 -> 读写之间串行](#1.4.1.2防用前另修改过期 -> 读写之间串行)

[1.4.2防止写入片段覆损 => 写块写入的数据 完整无损 -> 写串行](#1.4.2防止写入片段覆损 => 写块写入的数据 完整无损 -> 写串行)

2.读写之间

[2.1先写后读 - 线程安全(二).3:总](#2.1先写后读 - 线程安全(二).3:总)

2.1.1起因

2.1.2原因

2.1.3现象

②内存位置可见旧值

[2.1.4解决 - 刷新内存](#2.1.4解决 - 刷新内存)

[2.2先读后写 - 修改过期](#2.2先读后写 - 修改过期)

2.2.1起因

2.2.2原因

2.2.3现象

[2.2.4改善 - 写时拷贝(无法避免随机调度有先读后写有旧值)](#2.2.4改善 - 写时拷贝(无法避免随机调度有先读后写有旧值))

2.2.4.1利端

2.2.4.1.1写读内存只见一次

2.2.4.1.2写写之间线程安全

2.2.4.1.3读取数据新旧隔套

2.2.4.2弊端

2.2.4.2.1拷贝低效

2.2.4.2.2丢失数据

六、集合的线程安全

1.Collections.synchronizedGather(gather)

2.哈希表的线程安全

2.1Hashtable

2.2ConcurrentHashMap

[扩容迁移的写写并发时 写块已串行安全](#扩容迁移的写写并发时 写块已串行安全)

(1)原标的桶节点锁

(2)新表的CAS、红黑树节点级锁


一、线程创建(二):Thread类的构造方法、线程运行(二):Thread类的重写run方法

知识连接:

线程创建(一):可以/需要重写的方法、线程运行(一):Java程序的运行

1.Thread的构造方法

Thread类 传参初始化Runnable成员 进行构造

Thread作Worker类成员时

Worker类 ->【JavaEE】线程池ThreadPoolExecutor源码2w字详解 - CSDN博客

  • Worker类 实现Runnable接口 的重写run方法 ++执行外部类ThreadPoolExecutor的runWorker方法++

Thread成员构造时 传++自身Worker类实例++参this ++向上转型++初始化 ++Thread里存储的++ Runnable成员target


2.Thread的重写run方法

  • Thread类 实现Runnable接口 的重写run方法 ++执行Thread类存储的一个Runnable成员任务target++

Thread作Worker类成员时

(1)从己类Thread出发本层执行run

Worker类的成员Thread线程 调用start启动后 调用run 优先执行 已类 Thread的重写run方法 thread己身向上转型来 就没往下转 ++执行Thread类本层的run方法 里面再去执行Thread存储的Runnable任务++

(2)从己接口Runnable出发下层执行run

Runnable成员调用run 优先执行 己接口 Runnable的run方法 runnable己身向上转型来下转 到对应子类Worker ++执行转型层的重写run方法++

(1&2)方法调用

【JavaSE】多态 - CSDN博客

方法调用优先以已类方法执行查对象向上转型 而来 就下到执行转型层的重写方法


二、锁(四)synchronized&ReentrantLock

知识连接:

锁(一):对象的锁属性[作用/实现/修饰/危害]

锁(二):位置/阻塞/重入/连续

锁(三):锁策略

1.synchronized

synchronized是关键字,由JVM的C++代码实现

1.1加解锁

代码块加解锁:进代码块加锁出代码块解锁

synchronized加锁失败:

++synchronized加锁竞争失败++ ,锁 阻塞没锁线程 等待锁 唤醒阻塞 再重新去上锁竞争


1.2锁对象

++竞争的锁对象++ 由传入自定义


1.3公平性

默认且只能非公平锁


1.4自协调

锁内部 用Object类的wait/notify方法 ++自定协调++ 进行 弃锁 没锁 被锁阻塞持锁 用锁 唤醒阻塞


2.ReentrantLock

ReentrantLock是,由Java代码实现

2.1加解锁

方法加解锁:lock、trylock方法加锁unlock方法解锁

2.1.1lock加锁失败:

++lock加锁竞争失败++ ,锁 阻塞没锁线程 等待锁 唤醒阻塞 再重新上锁竞争

2.1.2trylock加锁失败:

++trylock加锁竞争失败++ ,返回false(++加锁竞争成功++ ,返回true),++时间参数等待时间再返回++


2.2锁对象

++竞争的锁对象++ 是自身实例


2.3公平性

默认非公平锁构造传true 实现公平锁


2.4自协调

锁内部 用Condition类的等待/通知方法 ++自定协调++ 进行 弃锁 没锁 被锁阻塞持锁 用锁 唤醒阻塞


三、信号量

信号量 计数 ++供给线程占用++ 的资源个数

1.限制同执线程数

++一个线程 可以持有 信号量的多个资源++ ,限制了++每个线程在持有最少一个资源 下的++++最多同时执行的线程个数++

1.1锁

总供给1个资源的 二元信号量,限制 同时++最多1个++线程 持有资源执行 ,即++++

1.2共享锁

总供给个资源的 多元信号量,限制 同时++可以++++多个++ 线程** 持有资源执行** ,即++共享锁++


2.申请释放资源

2.1acquire

线程申请资源P操作

2.2release

线程释放资源V操作


四、闭锁CountDownLatch类

1.new CountDownLatch(int count)

初始计数次数

2.countDown

计数减1次

3.await

阻塞线程计数次减完<=0


五、线程安全(一).5:总&线程安全(二).3:总&修改过期

多个线程 并发访问 同一变量 有写

1.写写之间 - 线程安全(一).5:总

知识连接:

线程安全(一).1:不安全原因和措施

线程安全(一).2:指令全排序

线程安全(一).3:条件产生渡送执行

线程安全(一).4:写块串行保安全

1.1起因

多个线程 并发****写 同一 变量

1.2原因

写块++非原子++


1.3现象

非原子写块++互碎++ 使得 ++写块的 读取用前过期写入片段覆损++

1.3.1读取用前过期
①过期旧值

"****读取的数据读的变量 使用/修改++[++ 互碎另写的碎片来的]后 过期**"**

①.1用前过期旧值

写块互碎后可能发生 读取的数据读取后使用前 有另线程并发 修改/使用读变量用前****过期,++使用过期值++

①.2用后过期旧值

读取的数据读取后使用后 再另线程并发 修改/使用读变量 变为 用后****过期的旧值

1.3.2写入片段覆损

" 写入的数据 都会互覆 "

写块互碎后 可能发生 写入的数据 互相在 写到半未写完时片段覆****损


1.4解决 - 串行化

++串行原子化++写块 防止++互碎++ ++的 读取用前过期写入片段覆损++

1.4.1防止读取用前过期 => 写块读取的数据 撑得住新

防止另外线程读取后使用前 并发 使用/修改 读取变量 使读取数据 用前过期

1.4.1.1防用前另使用过期 -> 读串行

读变量1串行 **无外线程并列地 ++并发++**++去读++ 出 串行用下注定排成 读取数据 使用时已用完用前过期的数据

1.4.1.2防用前另修改过期 -> 读写之间串行

读变量1与写变量2串行 无外线程穿插在中间地 ++并发++++写改++ 读变量1 使读取数据 使用前被修改用前****过期

1.4.2防止写入片段覆损 => 写块写入的数据 完整无损 -> 写串行

写变量2串行 无外线程互穿插地 ++并发++****++互写++ 使完整的写 成片段地互相覆盖 覆损数据


2.读写之间

2.1先写后读 - 线程安全(二).3:总

知识连接:

线程安全(二).1:不安全原因和措施

线程安全(二).2:内存可见性

2.1.1起因

多个线程 并发****先写后读 同一变量

2.1.2原因

内存++可见性++

2.1.3现象
②内存位置可见旧值

++读取不到++ 已执写最新值所在的内存 使得 读取非时新值

2.1.4解决 - 刷新内存

volatilesynchronized 强制读写 共同的主内存


2.2先读后写 - 修改过期

2.2.1起因

多个线程 并发先读后写 同一变量

2.2.2原因

线程单位 随机调度****有 所有的相对执行顺序

2.2.3现象

++随机下 一定会有 先读后写 调度++ ,读线程先读取的数据 不管用前被写线程修改读变量而过期 还是自己用后已过期,写线程在后修改读变量后读取数据一定变过期


2.2.4改善 - 写时拷贝(无法避免随机调度有先读后写有旧值)

并发读写相同变量时,每对读写拷贝多一份变量 分开读写内存地 进行并发

2.2.4.1利端
2.2.4.1.1写读内存只见一次

写读并发 分开内存时 不会有 先写后读共同内存的 可见性问题:延后并减少成 只在指针赋值修改后 读取新数组的已修改数据时的一次


2.2.4.1.2写写之间线程安全

原子写写 共同内存并发赋值修改 指针 指向 非原子 写写 各自内存并发修改 好的新数组,指针写写数组写写线程安全


2.2.4.1.3读取数据新旧隔套

读写并发 分开内存时 不会有 先读后写共同变量的 修改过期问题:延后并减少成 只在指针赋值修改 指向改好的新数组后 读取数据 由全新变全旧地 整套地过期一次数据新旧不互掺地隔套读取

应用 - 服务器修改配置

修改服务器的配置文件时,通过 停机服务无读取写时拷贝新旧套读 避免 服务器读取 ++新旧互掺++的配置

(1)停机服务

服务器停机 关闭服务客户端 无配置读取地 修改配置

(2)写时拷贝

启动 ++单个++ 修改配置的++写++线程读取配置的++多个读++线程 只构成++一对读写++++拷贝一份++原配置

(2).1线程安全

++单个写++线程 修改原配置++多个读++线程 读取拷贝的共同一个配置 线程安全

(2).2不丢数据

只构成++一对读写++ 只有++一个新数组++ 修改数据不会被整数组互覆盖丢失

(2).3新旧套隔

  • 写线程修改完配置前:读线程全新地读取配置
  • 写线程修改完配置更新指针后:读线程读取的配置由全新变全旧地 整套过期

读取的配置 新旧隔套 不会互掺


2.2.4.2弊端
2.2.4.2.1拷贝低效

多对地并发 读写相同变量 且 变量内存巨大 时,拷贝 多份巨大的变量 开销很大

2.2.4.2.2丢失数据

多对地 并发读写 相同变量时修改数据零散独立在多个新数组中 被整数组互覆盖丢失


六、集合的线程安全

1.Collections.synchronizedGather(gather)

集合的公共方法 加上synchronized锁修饰


2.哈希表的线程安全

2.1Hashtable

Hashtable全部方法整表this实例 上锁 串防 对表的所有并发操作

2.2ConcurrentHashMap

ConcurrentHashMap写方法修改所处桶的头节点 上锁 串防 ++只在同桶区域++ ++才有可能对同节点 才可能有危险++ 的并发有写操作

扩容迁移的写写并发时 写块已串行安全
(1)原标的桶节点锁

写块的 读串行读写间串行 用++原表++ 的桶节点锁实现

(2)新表的CAS、红黑树节点级锁

写块的 写串行 用++新表++ 在桶链表时的CAS尾插next 或 在桶红黑树时的节点级锁实现

相关推荐
顾安r7 小时前
12.15 脚本网页 bash内建命令
java·前端·javascript·html·bash
hellotutu7 小时前
Java 读取 Excel 文件
java·开发语言·excel
胡萝卜3.07 小时前
构建安全的C++内存管理体系:从RAII到智能指针的完整解决方案
运维·开发语言·c++·人工智能·安全·智能指针·raii
MSTcheng.7 小时前
【C++】如何快速实现一棵支持key或key-value的二叉搜索树?关键技巧一文掌握!
开发语言·c++·算法·二叉搜索树
ByNotD0g7 小时前
Go 泛型 in 1.25
开发语言·后端·golang
野生风长7 小时前
从零开始的c语言:指针高级应用(下)(回调函数,qsort函数模拟实现, strlen和sizeof)
java·c语言·开发语言·c++·算法
g***B7387 小时前
Java 服务端架构的本质:从单体到云原生的演进与思维模式变革
java·云原生·架构
d111111111d7 小时前
嵌入式面试问题:STM32中指针和数组的本质区别是什么,常用数组存储什么数据?
java·笔记·stm32·单片机·嵌入式硬件·学习
chao1898447 小时前
C# 实现画板源码
开发语言·c#