1、基本的并发包
- java.util.concurrent 并发包
- java.util.concurrent.atomic 原子性
- java.util.concurrent.locks 锁相关
并发与并行的区别:并发是多个线程公用一个资源、并行是做一件事不同的步骤同时执行。
2、通过Java关键字volatile引入 @VolatileDemo
volatile:Java虚拟机提供的轻量级的同步机制
- 保证可见性
- 不保证原子性
- 禁止指令重排
3、JMM(Java内存模型)
关键特点:
- 可见性
- 原子性
- 有序性
有序性:
volatile为什么能禁止指令重排?:内存屏障(Memory Barrier),一个cpu指令。
volatile通过插入读屏障和写屏障保证可见性,在volatile禁止重排序上,也是通过内存屏障实现的。 因为内存屏障可以使一些指令按照特定顺序执行。 volatile禁止指令重排序的规则: 1.当第二个操作是voaltile写时,无论第一个操作是什么,都不能进行重排序 2.当地一个操作是volatile读时,不管第二个操作是什么,都不能进行重排序 3.当第一个操作是volatile写时,第二个操作是volatile读时,不能进行重排序
这只是《Java虚拟机规范》中,对内存模型中主内存和线程工作内存的交互中规定的,是为了屏蔽不同的硬件和操作系统的数据访问细节。具体的规范是对操作JVM的字节码指令的规范中,比如主内存与线程工作内存的交互指令read、load、use、assign、store、write。不同平台和不同的厂商的不同版本的JVM有不同的实现,比如HotSpot、Jrocket、Sun Classic JVM。
读取速率:硬盘 < 内存 < cpu
由于速度的差异,cpu不能干等内存。故内存与cpu之间存在 缓存。
可见性:t1线程的工作内存修改了从主内存拷贝来的age,修改后赋值给主内存,若t2与t3等线程也可以更新为37,则为可见。
原子性: 不可分割,要么同时成功,要么同时失败
若不满足原子性,多线程n++操作的写覆盖导致数据丢失
4、CAS @CASDemo
什么是CAS:比较并交换。是一条CPU并发原语
线程在主内存中拷贝数据时会先拿到一个期望值,在线程工作内存中执行完后会检查当前值是否是期望值,若是则将执行后的值赋给主内存。
相较于synchronized,CAS不加锁不但保证了一致性同时也保证了较高的并发性。
CAS底层原理:自旋锁 与 UnSafe
原子类 AtomicInteger 的 getAndIncrement 方法:
UnSafe类:
- 上图是一个线程中的自旋锁,var1(对象地址)的var2(该对象中某个属性的偏移量)对应一个值var5。while中不断比较:
- var1与var2表示最新时刻的值,var5是刚刚获取的值,两者进行比较。若一致则跳出自旋锁,更新值。不一致则重新读取主内存的值赋给var5。
- var5都是在主内存读取。
- var5这个value被volatile修饰,所以具有线程间的可见性。
不仅仅只有整型的原子操作,自定义的原子操作通过原子引用实现: Class AtomicReference<> @ARDemo
CAS缺点
- do while 自旋循环时间长,一直占用CPU开销很大
- 只能保证 一个 共享变量的原子操作
- 产生 ABA 问题
ABA问题: 线程2将主内存的值更改了,然后又改回来了!这时候线程1是不知道的,所以线程1以为没人动过。
那么如何进一步解决ABA问题?
- 新增一种机制:时间戳
AtomicStampedReference<>
。相当于版本号 @ABADemo
5、Class CountDownLatch @CountDownLatchDemo
作用:控制 其他线程都完成了,最后一个线程再执行最后操作。减到0 唤醒最后线程
6、Class CyclicBarrier @CyclicBarrierDemo
作用:控制 其他线程都完成了,最后一个线程再执行最后操作。加到屏障 唤醒最后线程
7、Class Semaphore @SemaphoreDemo
信号量:主要用于两个目的:
- 用于多个共享资源的互斥使用
- 用于并发线程数的控制
8、创建线程的第三种方式 Callable @CallableDemo
9、线程池 @MyThreadPoolDemo、
ThreadPoolExecutor 七大参数: