java并发编程学习笔记(一)

lock前缀的指令会在多核处理器下引发两件事情:

1、将当前处理器的缓存行的数据写会到系统内存。
lock前缀指令导致在执行指令期间,声明处理器lock#信号,在多处理器环境中,lock#信号确保在声明该信号期间,处理器可以
独享内存。在最近的处理器中,lock#信号一般不锁总线,而是锁缓存。
2、这个写会内存的操作会使在其他cpu里的缓存了该内存地址的数据无效。
处理器会使用嗅探技术保证它的内部缓存、系统内存和其他处理器缓存的数据在总线上保持一致---缓存一致性原则


synchronized的实现原理与应用

java中每一个对象都可以作为锁,具体表现在一下三种形式:
1、对于普通同步方法,锁是当前实例对象
2、对于静态同步方法,锁是当前类的Class对象
3、对于同步方法块,锁是synchronized括号里配置的对象。
jvm基于进入和退出Monitor对象来实现同步和代码块同步,但两者的实现细节不一样,代码块同步使用monitorenter和monitorexit
指令实现。monitorenter指令是在编译后插入到同步代码块的开始位置,而monitorexit是插入到方法结束处和异常处。jvm要保证
每个monitorenter必须有对应的monitorexit与之对应。


锁一共有4中状态

级别从低到高依次是:无锁状态、偏向锁状态、轻量级锁状态、重量级锁状态。这几个状态会随着竞争情况逐渐升级。
锁可以升级但是不能降级,以为这偏向锁升级成轻量级锁后将不能降级为偏向级锁。

偏向锁

偏向锁加锁:
当一个线程访问同步块并获得锁时,会在对象头和栈帧中的锁记录里存储偏向锁的线程ID,以后该线程在进入和退出同步块时不需要
进行CAS操作来加锁和解锁,只需要简单的测试一下对象头的Mark Work里是否存储着指向当前线程的偏向锁。如果测试成功,表示已经
获得了锁,如果测试失败,则需要在测试一下Mark Word 中偏向锁的标识是否设置成1:如果没有设置,则使用CAS竞争锁;如果设置了
则尝试使用CAS将对象头的偏向锁指向当前线程。
偏向锁撤销:
它会首先暂停拥有偏向锁的线程,然后检查持有偏向锁的线程是否还活着,如果线程不处于活动状态,则将对象设置成无锁状态,如果
如果线程仍然状态,拥有偏向锁的栈会被执行,遍历偏向对象的锁记录,栈中的锁记录和对象的Mark Word要么重新偏向于其他线程,要么
恢复到无锁或者标记对象不合适作为偏向锁。

轻量级锁

轻量级锁加锁
线程在执行同步块之前,JVM会先在当前线程栈帧中创建用于存储锁记录的空间,并将对象中的Mark Wrod复制到锁记录中。
轻量级锁解锁
轻量级解锁时,会使用原子的CAS操作将Mark Word 替换回到对象头,如果成功,则表示没有竞争发生,如果失败,表示当前锁存在
竞争,锁会膨胀成重量级锁。

处理器如何实现原子操作

使用总线锁保证原子性

1、第一个机制是通过总线锁保证原子性:处理器使用总线锁来解决这个问题。所谓总线锁就是使用处理器提供的一个lock#信号,当一个
处理器在总线上输出此信号时,其他处理器的请求将被阻塞住,那么该处理器可以独占共享内存。
使用缓存锁保证原子性
2、第二个机制是通过缓存锁保证原子性:所谓“缓存锁定”是指内存区域如果被缓存在处理器的缓存行中,并且在lock操作期间被锁定,那么
当它执行锁操作回写到内存时,处理器不在总线上声明lock#信号,而是修改内部的内存地址,而是修改内存的内存地址,并允许他的缓存一
一致性机制来保证操作的原子性,因为缓存一致性机制会阻止同时修改有两个以上处理器缓存的内存区域数据,当其他处理器回写已被锁定
的缓存行数据时,会使缓存行无效。

CAS实现原子操作的三大问题

1、ABA问题
因为CAS需要在操作值得时候,检查值有没有发生变化,如果没有发生变化,则更新,但是如果一个值原来是A,编程了B,又编程了A,那么使用
CAS进行检查时会发现他的值没有发生变化,但是实际上已经发生了变。ABA问题的解决思路就是使用版本号,在变量前面追加上版本号,每次
变量更新的时候把版本号加1.
2、循环时间长开销大
自旋CAS如果长时间不成功,会给CPU带来非常大的执行开销,如果JVM支持处理器提供的pause指令,那么效率会有一定的提升,pause指令有两个
作用:第一,它可以延迟流水线执行指令(de-pipeline),使CPU不会消耗过多的执行资源,延迟时间取决于具体实现的版本,在一些处理器上
延迟时间是零。第二,他可以避免在退出循环的时候因内存顺序冲突而引起CPU流水线被清空,从而提高CPU的执行效率。
3、只能保证一个共享变量的原子操作
当对一个共享变量执行操作时,我们可以使用循环CAS的方式来保证原子操作,但是对多个共享变量操作时,循环CAS就无法保证操作的原子性
这个时候就可以使用锁,还有一个取巧的方法,就是把多个共享变量合并成一个共享变量来操作。eg:i=2,j=a,合并一下ij=2a;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
嗨!很高兴回答你关于Java并发编程的问题。请问你想知道什么方面的内容呢?我可以分享一些学习笔记和建议给你。 1. 并发编程基础:了解并发编程的基本概念,如线程、进程、锁、同步等。学习Java中的并发编程模型以及相关的API,如Thread、Runnable、Lock、Condition等。 2. 线程安全性:学习如何保证多线程环境下的数据安全性,了解共享资源的问题以及如何使用同步机制来防止数据竞争和并发问题。 3. 线程间的通信:掌握线程间的通信方式,如使用wait/notify机制、Lock/Condition等来实现线程的协调与通信。 4. 并发容器:学习并发容器的使用,如ConcurrentHashMap、ConcurrentLinkedQueue等。了解它们的实现原理以及在多线程环境下的性能特点。 5. 并发工具类:熟悉Java提供的并发工具类,如CountDownLatch、CyclicBarrier、Semaphore等,它们可以帮助你更方便地实现线程间的协作。 6. 并发编程模式:学习一些常见的并发编程模式,如生产者-消费者模式、读者-写者模式、线程池模式等。了解这些模式的应用场景和实现方式。 7. 性能优化与调试:学习如何分析和调试多线程程序的性能问题,了解一些性能优化的技巧和工具,如使用线程池、减少锁竞争、避免死锁等。 这些只是一些基本的学习笔记和建议,Java并发编程是一个庞大而复杂的领域,需要不断的实践和深入学习才能掌握。希望对你有所帮助!如果你有更具体的问题,欢迎继续提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

fjkxyl

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值