百姓网站外推广怎么做,网站开发的相关语言有哪些,外贸网站APP,外贸怎么做起来文章目录 1、synchronized关键字的底层原理#xff1a;Monitor2、synchronized相关2.1 为什么说synchronized是重量级锁2.2 synchronized锁升级之偏向锁2.3 synchronized锁升级之轻量级锁 3、Java内存模型JMM4、CAS4.1 CAS流程4.2 CAS底层实现 5、volatile关键字的理解5.1 可见… 文章目录 1、synchronized关键字的底层原理Monitor2、synchronized相关2.1 为什么说synchronized是重量级锁2.2 synchronized锁升级之偏向锁2.3 synchronized锁升级之轻量级锁 3、Java内存模型JMM4、CAS4.1 CAS流程4.2 CAS底层实现 5、volatile关键字的理解5.1 可见性5.2 禁止指令重排 1、synchronized关键字的底层原理Monitor
synchronized互斥锁同一时刻最多只有一个线程能持有对象锁。用javap拿到synchronized示例代码的字节码信息 javap -v SyncTest.class可以看到synchronized底层自己上锁、解锁解锁两次是怕出现异常后导致锁不能释放第二个解锁相当于finally里释放锁 Monitor监视器由JVM提供c实现。每个对象实例都会有一个Monitor对象Monitor的结构 线程Thread1执行到synchronized代码块如果对象的Monitor对象的Owner属性为null则抢锁成功后面其他线程再进来抢锁就进入EntryList阻塞直到Thread1执行完释放锁EntryList里的线程又开始争抢锁并非先来后到的排队WaitSet即存调用了wait方法的线程 2、synchronized相关
2.1 为什么说synchronized是重量级锁
Java应用中的线程是用Thread对象来操作的JVM负责维护Java线程和操作系统原生线程之间的映射关系。阻塞和唤醒一个线程都需要CPU参与而调用硬件资源CPU只能是内核态操作且Java对象锁通过Monitor实现Monitor又通过操作系统的互斥量Mutex Lock实现。
因此加解锁、阻塞线程、唤醒线程等就涉及到了用户态和内核态的频繁切换两个空间的一些变量的值拷贝synchronized代码块短的话可能切换的时间比代码执行时间还长。所以synchronized称为重量级锁。 鉴于此JDK6以后为synchronized引入轻量级锁和偏向锁的概念避免一下就捅到重量级锁以尽量减少用户态和内核态的切换次数。
2.2 synchronized锁升级之偏向锁
优化场景一个锁一直被一个线程持有。如买票时发现线程t3一直在执行卖票的synchronized代码块 偏向锁会偏向于第一个访问锁的线程如果在接下来的运行过程中该锁没有被其他的线程访问则持有偏向锁的线程将永远不需要触发同步也即偏向锁在资源没有竞争情况下消除了同步语句。
【syncoronized偏向锁】
2.3 synchronized锁升级之轻量级锁
优化场景两个线程近乎可以错开交替执行, 或者说是有锁竞争, 但竞争不激烈的情况获取锁的冲突时间极端本质就是CAS自旋锁不要直接往重锁走。
【syncoronized轻量锁】 总之, synchronized的偏向锁和轻量级锁都是为了缓冲, 尽量避免走Monitor 操作系统的互斥变量来实现加解锁, 以减少用户态和内核态的切换, 实现性能提升
3、Java内存模型JMM
定义了线程工作内存和主内存之间读写操作的规范 每个线程有自己的工作内存, 每块线程的工作内存之间相互隔离, 操作同一个变量时, 可通过主内存分别save和load
【JMM】
4、CAS
4.1 CAS流程
比较再交换Compare And Swap一种乐观锁的思想在无锁的状态下保证线程操作数据的原子性CAS广泛用于AQS框架、AtomicXXX类
当前工作内存的值V旧的预期值A即将更新写回主内存的值B
示意代码: t1线程从主内存读到i51后准备把6写回主内存此时比较期望值5和内存中的实际i值若相等则乐观的认为自己运算的期间没有其他线程修改i就将i写回主内存。反之比如主内存i6那t1就再来一次i6i1期望6此时如果主内存i6则写回成功反之继续自旋。 CAS的优势是没有加锁线程不会陷入阻塞效率高反之如果竞争激烈频繁失败自旋重试效率低且消耗CPU
4.2 CAS底层实现
底层通过Unsafe类来直接调用操作系统底层的CAS指令来保证原子性CAS对应在底层是CPU的一条原子指令cmpxchg 最后CAS体现乐观锁的思想是不担心自己操作期间别的线程修改了共享变量如果被改了就吃点亏再重执行一次反正我从主内存读数据、在工作内存读数据、写回主内存三步不可再分有原子性保证撑死多试几次才能修改数据成功
反之synchronized则是悲观锁自己操作时要防着其他线程改共享变量上个锁我改完解锁之后别的线程才有机会
5、volatile关键字的理解
volatile修饰的变量 :
保证线程间的可见性禁止进行指令重排序
5.1 可见性
volatile的可见性即保证不同线程对某一个变量一旦完成更改其他线程立即可见因为会从线程的工作内存立马刷到主内存 执行结果: 结果分析三个线程操作一个共享变量stop线程1改了stop的值一会儿线程2就读到了这个变化但线程3却一直在循环这是因为JVM的即时编译器JIT对一直执行的热点代码做了优化 可加JVM参数-Xint禁用掉即时编译器但得不偿失可给共享变量加stopJIT不会对volatile变量做优化且volatile变量会立即刷回主内存
static volatile boolean stop true;重新运行显示循环16038233次后读到stop变量变为true了 5.2 禁止指令重排
看个案例用Actor注解保证方法内u的代码在同一个线程下执行 以上代码并发测试下出现1 ,0 的结果说明发生了重排序 用volatile修饰变量在读写共享变量时加入屏障阻止其他读写操作越过屏障以阻止指令重排序
//改为这样
int x;
volatile int y;此时并发测试下不再有1 ,0 的结果屏障如下 如果给x加volatile则还是有1, 0 的结果
//改为这样
volatile int x;
int y;因为此时的插入的屏障位置如下 上面volatile修饰x还是y这是一个volatile的使用技巧问题
写变量让 volatile 修饰的变量的在代码最后位置读变量让 volatile 修饰的变量的在代码最开始位置
详见volatile读写屏障