JMM和Lock

一 .**CPU

在这里插入图片描述
在这里插入图片描述

CPU怎么保证并发控制
(1) 关中断
(2)缓存一致性协议 每个硬件厂商 协议不同 常见的interl 的 MESI 通过四种状态 判断如上图
CPU的速度和内存的速度(100 :1)
这里的速度值得是ALU访问寄存器的速度比访问内存的速度快100倍
为了充分利用CPU的计算能力,在CPU和内存中间引入缓存的概念(工业上的妥协,考虑性价比)
现在的工业实践,多采用三级缓存的架构
缓存行:一次性读取的数据块
程序的局部性原理:空间局部性 时间局部性
如果缓存行大:命中率高,但读取效率低。如果缓存行小:命中率低,但读取效率高。
工业实践的妥协结果,目前(2021)的计算机多采用64bytes (64 * 8bit)为一行
由于缓存行的存在,我们必须有一种机制,来保证缓存数据的一致性,这种机制被称为缓存一致性协议。
(3)系统屏障
保证系统运行顺序 比如voliate

二. 内存模型

java 内存模型 JMM
Java中所有变量都储存在主存中,对于所有线程都是共享的。每条线程都有自己的工作内存(Working Memory),工作内存中保存的是主存中某些变量的拷贝,线程对所有变量的操作都是在工作内存中进行,线程之间无法相互直接访问,变量传递均需要通过主存完成。
主内存: 共享资源
工作内存:copy 主内存

jVM 内存模型

java 运行时的数据去,垃圾回收器负责回收,动态分配内存,垃圾回收器会定时收走不用内存
优点:动态分配内存大小
缺点:由于要在运行时动态分配,所以会存取速度慢 (扩容)
() 存放引用地址大地方
优点:存储数据快,仅次于计算器cpu 寄存器,
缺点:大小固定 比如 8大基本类型
方法区 存储类信息、常量、静态变量、即时编译器编译后的代码。
程序计数器 程序计数器,线程私有、指向下一条要很执行的指令
本地方法区 为虚拟机使用到的Native 方法服务

1.java 并发编程的三个概念
原子性: 一个或多个 要执行过程中不会被其他因素打断,要么就都不执行
可见性: 多线程当中 一个线程改变某个值 其他线程都可以看到
有序性: 为了充分利用CPU 代码可能会不按照顺序执行 防止指令重排,按照代码的顺序执行
(1) voliate 可见性 指令重排 A 修改了值 B 能知道. 让B 不要在都本地内存
ACC_VOLIATE (JVM)->CPU(汇编指令)
使用场景:状态标记
(2)(hanppes-before 原则 )
(3)JVM中的内存屏障 LoadLoadBarrier LoadStoreBarrier StoreLoadBarrier StoreStoreBarrier

2.hanppens-before原则(JVM规定重排序必须遵守的规则)

•程序次序规则:同一个线程内,按照代码出现的顺序,前面的代码先行于后面的代码,准确的说是控制流顺序,因为要考虑到分支和循环结构。

•管程锁定规则:一个unlock操作先行发生于后面(时间上)对同一个锁的lock操作。

•volatile变量规则:对一个volatile变量的写操作先行发生于后面(时间上)对这个变量的读操作。

•线程启动规则:Thread的start( )方法先行发生于这个线程的每一个操作。

•线程终止规则:线程的所有操作都先行于此线程的终止检测。可以通过Thread.join( )方法结束、Thread.isAlive( )的返回值等手段检测线程的终止。

•线程中断规则:对线程interrupt( )方法的调用先行发生于被中断线程的代码检测到中断事件的发生,可以通过Thread.interrupt( )方法检测线程是否中断

•对象终结规则:一个对象的初始化完成先行于发生它的finalize()方法的开始。

•传递性:如果操作A先行于操作B,操作B先行于操作C,那么操作A先行于操作C

3 .内存同步 volalite
用volatile修饰的变量,线程在每次使用变量的时候,都会读取变量修改后的最的值。volatile很容易被误用,用来进行原子性操作
就是 线程1,2同时从主内存取值到工作内存中,线程2修改值之后同步到主内存中,那么会强制1 从主内存从新读取.
在这里插入图片描述
四 锁

1.Synchronized monitotenter \monitotenterexit 底层jvm 监视器 很多参数 (让线程等待)

概念 重量级锁 和重入锁(反复上锁) jvm 锁

使用
Synchronized
(1) 方法(ACC_Synchronized)
Synchronized m(){ //锁对象
}

(2)代码块
Synchronized (A.class){
}

(3) j静态方法(锁类)
Synchronized m(){
}

在这里插入图片描述

在这里插入图片描述

两者区别
a. 对于普通同步方法 锁时当时实例对象
b.静态同步方法 锁时当前类对象
c. 静态代码块 锁 括号里面的

场景
竞争资源

2.lock 轻量级锁 手动锁 手动释放
ReentrantLock 轻量级锁,重入锁(可以反复上锁) 他可以分为公平锁和非公平锁 默认非公平的
(多看看里面方法) lock 和tryLock 可以等待一些时间再去获取,获取不到就算了(乐观锁)
try{
lock()
}catch(Exception e){
}finally{

//这里需要加入isHeldByCurrentThread 判断当前线程数量 需不需要释放锁,如果都没加锁 没必要释放
if(*.isHeldByCurrentThread()){
unlock
}
}
ReentrantLock 底层有个Condition (条件 )
Condition 生产 和消费 ,生产满了 就去消费 ,消费块没了 就去生产

3.cas :
⾸先,每个线程都会先获取当前的值,接着⾛⼀个原⼦的 CAS 操作,原⼦的意思就是这个 CAS 操作⼀定是⾃⼰完整执⾏完的,不会被别⼈打断。 然后 CAS 操作⾥,会⽐较⼀下说,唉!⼤兄弟!现在你的值是不是刚才我获取到的那个值啊? 如果是的话,bingo!说明没⼈改过这个值,那你给我设置成累加 1 之后的⼀个值好了! 同理,如果有⼈在执⾏ CAS 的时候,发现⾃⼰之前获取的值跟当前的值不⼀样,会导致 CAS 失 败,失败之后,进⼊⼀个⽆限循环,再次获取值,接着执⾏ CAS 操作!

在这里插入图片描述CAS ABA 问题
Thread 1,Thread2,Thread 3 原值是10 Thread 1 改为20 Thread2 改为10 那么Thread3 读取到值时10 那么Thread3 会认为值没被更改

解决办法 加 标记

Atomic 体系

AtomicInteger:是对int 类型一个封装,提供原子性和更新操作

AtomicBoolean 等同于voalite
场景: 可以用于程序启动

在这里插入图片描述

场景 :
并发统计

原理:
cas 全称 compare And Swap 比较替换 其核心算法思想如下
函数 CAS(V,E,N) 参数:V 表示跟新的变量 E 预期值 N 新值

4.StampedLock 和 ReentranReadWriteLock 悲观锁 读写锁
写的时候上锁独享 不给其他人用,读到时候可以多个线程共享

5.AbstractQueuedSynchronizer 队列同步器 锁的底层 核心 核心 核心
在这里插入图片描述

底层实现原理
链表 和队列

6.CountDownLatch
允许一个或者多个线程等待其他线程完成操作

在这里插入图片描述场景
并行计算
依赖启动

7.semaphore 信号量 和rentrantlock 方法很像
用来控制同时访问特定资源的 线程数量,他通过协调各个线程 保证合理使用公共资源
场景
限流和秒杀

限流

  1. redis+lua 分布式
  2. semaphore (JVM)
    如果分布式 每台服务器 性能不一样,能接受的并发量不一样,那我们可以利用jvm 用 semaphore控制并发量

**8.condition 条件/状态 可以await()可以有多个等待室而object的wait 只有一个和signal()

Condition是在java 1.5中才出现的,它用来替代传统的Object的wait()、notify()实现线程间的协作,相比使用Object的wait()、notify(),使用Condition的await()、signal()这种方式实现线程间协作更加安全和高效。因此通常来说比较推荐使用Condition,阻塞队列实际上是使用了Condition来模拟线程间协作。

Condition是个接口,基本的方法就是await()和signal()方法;
Condition依赖于Lock接口,生成一个Condition的基本代码是lock.newCondition()
调用Condition的await()和signal()方法,都必须在lock保护之内,就是说必须在lock.lock()和lock.unlock之间才可以使用
  Conditon中的await()对应Object的wait();

Condition中的signal()对应Object的notify();

Condition中的signalAll()对应Object的notifyAll()。

condition可以通俗的理解为条件队列。当一个线程在调用了await方法以后,直到线程等待的某个条件为真的时候才会被唤醒。这种方式为线程提供了更加简单的等待/通知模式。Condition必须要配合锁一起使用,因为对共享状态变量的访问发生在多线程环境下。一个Condition的实例必须与一个Lock绑定,因此Condition一般都是作为Lock的内部实现。

await() :造成当前线程在接到信号或被中断之前一直处于等待状态。
await(long time, TimeUnit unit) :造成当前线程在接到信号、被中断或到达指定等待时间之前一直处于等待状态
awaitNanos(long nanosTimeout) :造成当前线程在接到信号、被中断或到达指定等待时间之前一直处于等待状态。返回值表示剩余时间,如果在nanosTimesout之前唤醒,那么返回值 = nanosTimeout - 消耗时间,如果返回值 <= 0 ,则可以认定它已经超时了。
awaitUninterruptibly() :造成当前线程在接到信号之前一直处于等待状态。【注意:该方法对中断不敏感】。
awaitUntil(Date deadline) :造成当前线程在接到信号、被中断或到达指定最后期限之前一直处于等待状态。如果没有到指定时间就被通知,则返回true,否则表示到了指定时间,返回返回false。
signal() :唤醒一个等待线程。该线程从等待方法返回前必须获得与Condition相关的锁。
signal()All :唤醒所有等待线程。能够从等待方法返回的线程必须获得与Condition相关的锁。

在这里插入图片描述

总结
javap -i **.class 字节码生成
jni java native intenrface java和c 之间的调用
voalite:防止指令重排,并单纯的读,写可以代替简单的锁,但是不保证原子性
cas :保证原子性,是整个并发包的基础
aqs 定义铜鼓队列等待队列,并发包的基础,其他的锁很多都是基于aqs拓展实现的

公平锁 和非公平锁(NofairSync)
一个线程过来公平锁先排序(进入等待队列),非公平锁表示 我先要抢抢试试,成功了先执行,不成功就去排队

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值