并发编程学习基础篇
Posted adventure.Li
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了并发编程学习基础篇相关的知识,希望对你有一定的参考价值。
相关说明
该文章相关的学习笔记及练习代码将会放在个人 github, 博主也会尽量进行github的日更新,博客将会不定期进行更新,在更新的过程可能存在诸多不足的地方,愿大家指出,可博客私信/评论,也可QQ :674619459 联系我,一起讨论,还可以在GitHub上面提issue 。欢迎大家关注我的github,一起学习Java,一起进步!!。
一、学习目标
- 学习并发编程思维(OS的进程、线程管理)及海量业务处理
- 熟悉Java并发编程API的使用(可结合JDK源码进行分析)
- 结合nacos等开源框架分析并发编程的设计,提升设计能力
二、相关书籍
- 操作系统内功
- 见计算机基础部分
- Java并发书籍
- java 并发编程从入门到精通:从基础概述到线程安全、API及线程池框架等使用
- java 并发编程的艺术:比较贴近实操,API及JVM的内存模型等
- java 并发编程实战:和并发编程的艺术类似
- Java并发实现原理:JDK源码剖析 ,深入地进行剖析讲解。
- 相关官网推荐
- ifeve.com :并发编程网
- https://docs.oracle.com/javase/8/docs/technotes/guides/concurrency/index.html:java 并发官方文档
本次目录
线程并发基础篇
一、概念部分
CPU核数、线程数
- 关于位宽,内存,最大寻址的问题
- 虚拟内存 = min最大CPU寻址,磁盘外存大小
- 当操作系统一般为32bit或64bit;32bit的最大内存可以为4G;理论上64bit的最大内存为 2^34 G,可实际上的64bit内存一般为128、256G;
原因:主板限制(木桶效应), 相关讨论: https://www.zhihu.com/question/29962475/answer/1644236272
64位架构(windows的)下,地址线是46个,所以最大的物理地址是2^46B,折合64TB,可用地址空间也是这么大(目前为止)
- CPU核心数、线程数
- 为了实现并发或并行,有两种途径(CMP-多核心角度,STM-多线程角度)
- 核数和线程数的关系:一般为1:1,在引入超线程后为1:2
查看核数:
- linux: 于 /proc/cpuinfo文件中: processor:线程数, codeid:核心数 cat /proc/cpuinfo
- 注:在使用cat /proc/cpuinfo时,单核则显示一个核的信息,多核就显示过个 (截图如下)
- Java:可通过 getRuntime().availableProcessors()获取
- 注:nacos在PropertiesUtils中设计使用到(JDK 中的ConcurrentHashMap也有使用到),见以下截图
时间片机制(RR调度)
- 时间片的基本概念
掌握要点:
- 理解**进程(而不是线程)**的状态及其转换、管理机制(相关队列)
- 理解上下文切换和时间片的协调()上下文切换:CPU的利用效率,时间片:用户的响应速度 ;时间片:100ms适中
- 画进程状态模型图-结合进程队列、线程
进程、线程相关概念
- 软件、系统、程序、进程、线程(暂略)
并行、并发相关概念
- 并行、并发(暂略)
- 计算并发量的示例
- 吞吐量的概念
对于系统吞吐量:
- 同步、异步
为什么需要并发编程及注意事项
- 背景需求角度
- 海量数据处理、多用户
- 优点特性(实则也是为需求而生)
- 充分利用CPU资源
- 加快响应速度
- 代码模块化、异步化、简单化
- 注意点
- 线程安全问题:由于线程可用通信,共享资源,则在多个进行写操作,会存在线程安全问题
- 死锁问题:由于线程安全引入锁,需要防止死锁
- 资源耗尽导致死机:线程数过多时会导致 内存泄露 ? 资源耗尽 — 采用资源库设计,数据库连接采用该设计
二、认识Thread
Java中的线程转换(结合进程状态模型)
- 画图理解+Java代码练习
Java线程的实现方式(严格来说三种,广泛是四种)
相关参考博客:https://blog.csdn.net/bj_ameng/article/details/115266696
- Java中Thread的实现方式
- 继承Thread : 只能继承一个父类—思考局限?? —- 实际上实现run本来也无需复用多个??
- 实现Runnable接口:
- 实现Callable接口:
- 采用线程池Executors:
- 线程组的使用【可归纳为Thread的基本使用中】
构造函数:private ThreadGroup() ;public ThreadGroup(String name); 为什么这样设计?
Thread的基本API和使用
- 基本API
官方文档: https://docs.oracle.com/javase/8/docs/api/
- 中断机制
注:Java并没有提供安全终止线程的方法
(1)采用Thread.stop():已不推荐使用
(2)采用interrupt机制
- 守护线程
- 线程的异常处理
- 结合异常处理机制学习
线程副本ThreadLocal
- 【最清晰】ThreadLocal和局部变量和成员变量的区别
ThreadLocal是进程级别的全局变量。
最近有⼀个疑惑:为什么线程类的局部变量不能完全替代ThreadLocal,每⼀次new 线程都是创建了⼀个副本啊照理来说也是独⽴的,为什么还需要ThreadLocal。实际上确实是独⽴的,但是答案是ThreadLocal还有更⼴泛的⽤途。
- 第⼀种情况:
当想在不同线程,访问“同⼀个对象的⽅法”,希望以线程作为区分,区分⼀个变量的作⽤域,⽽希望这个⽅法根据线程不同⽽作出不同处理,这时就需要threadLocal(⽽不能⽤类成员变量,为啥呢,因为同⼀个对象,它的成员变量是⼀样的)。 - 第⼆种情况:
那为啥不⽤函数局部变量呢,因为⼜考虑到函数间局部变量不便于共享(试想如果⼀个线程执⾏了多个⽅法,他们如果想共享变量,如果是局部变量,则必须要不断传参,这样特别⿇烦,于是有了ThreadLocal,根据当前在哪个线程⽽获得变量)
想必读到这⾥,⼤家已经了解了ThreadLocal的使⽤场景了吧,实际上在使⽤ThreadLocal时时刻记得它是以线程为作⽤域的,就不会出错啦,⽽那些局部变量和成员变量的滥⽤,会导致程序可读性变差,⽽多线程时也有可能因为作⽤域⽽产⽣意想不到的奇怪问题。
- 原理概述
ThreadLocal维护⼀个静态map,key是线程,value是table数组。所以不同线程得到的table不同。
三、线程安全
初步了解JMM
- 背景
- 关于计算机的内存模型机制:内存 → 高速缓存 → 寄存器,由于有些数据使用频繁,因此就会放在缓存,而不是都从主存拿数据。
- JMM机制:主存+工作内存;主内存:堆存储,共享静态变量等;工作内存:局部变量,拷贝副本
- 多线程同时操作时带来的问题点: 数据的可见性,操作的时序性
- 两大问题
- 可见性问题
(1)将主内存复制变量到工作内存(read and load)
(2)执行代码,修改共享变量(use and sign)
(3)将工作内存刷新到主内存(store and write)
- 时序性问题
线程安全问题
- 不安全
当多个线程修改同一数据结构(可为集合,也可为变量)时,产生的数据不一致性问题,线程不安全。
- 线程安全
和线程不安全相反,每次都能保证一样的结果,保证数据的高度一致性和准确性。
保证的方式:
- synchronized : 加锁
- locks: ReetrantLock
- concurent下的包(atomic)
隐式锁 - 线程同步锁 synchronized
- 基本概念
Java自带的关键字(底层原理?—),保证线程同步,需要抢锁
- synchronized的加锁位置
(1)加在方法声明处(加在静态方法则是锁该类,加在非静态则是该对象)
(2)代码块:
- 锁住对象(this,Object):尽量使用分配内存较小的对象,例如 byte;抢锁释放锁,需要资源,对象越大资源处理越大。
- 锁住静态类( .class)
- 加锁的规则(考虑静态、非静态和加锁方式)
当加锁在 .class时锁住整个类,静态方法都不能用;而锁在 object只是该对象,静态方法是能够用的,;当存在静态方法时一般会采用加锁 .class
四种加锁情况: https://baike.baidu.com/item/synchronized/8483356?fr=aladdin
- 加在this: 所有该对象都不能被调用
- 加在obejct: 加了该对象锁的地方不能用
- 加在.class: 包括静态方法、静态变量都不能用
显示锁 - Lock, ReentrantLock, StampledLock
-
Lock及ReentrantLock
-
ReadWriteReetrantLock
ReadLock的意义在于保证读取的顺序性。
- StampedLock
什么是死锁
volatile和atomic
- volatile的作用
- 保证可见性:读取时是从内存地址拿数据,而非缓存,但并没有保证原子性,因为没有使其立刻写回内存
注:加锁即保证原子性也保证可见性。
- atomic
实现原理:
CAS算法,底层CPU指令实现
四、线程安全集合类
- 待分析
-
Hashtable 和 ConconrrentHashmap
-
CopyOnwirteArraysList\\Set
-
Vector
以上是关于并发编程学习基础篇的主要内容,如果未能解决你的问题,请参考以下文章