2.线程安全关键字syncnized的实现原理?
- 悲观锁和乐观锁
- 悲观锁:总是假设最坏的情况,每次去拿数据时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会被阻塞知道它拿到锁,如synchronized和ReentrantLock
- 乐观锁:总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是再更伤心的时候会判断下再次期间别人有没有更新这个数据。
- 乐观锁一般使用版本号机制或者CAS算法实现
- ABA问题是乐观锁的一个常见问题:如果一个变量V初次读取时候是A值,并且在准备赋值的时候检查到它仍是A值,那么我们就能说明他的值没有被其他线程修改过吗?A-B-A,JDK1.5之后提供了AtomicStampedReference
- 循环时间长开销大:自旋CAS长时间不成功,会给CPU带来非常大的执行开销
- 只能保证一个共享变量原子操作
- CAS(Compare And Set或 Compare And Swap)解决多线程并行情况下使用锁造成性能损耗的一种机制
- 包含三个操作数:内存位置(V),预期原值(A),新值(B)。如果内存位置的值与预期值匹配,那么处理器会自动将该位置的值更新为新值;否则,处理器不做任何操作。
- Happens-before原则定义
- 如果一个操作happens-before另一个操作,那么第一个操作的执行结果将对第二个操作可见,而且第一个操作的执行顺序排在第二个之前
- 两个操作之间存在happens-bofore关系,并不意味着一定要按照happens-before原则制定的顺序来执行。如果重排序之后的执行结果与按照happens-before关系来执行的结果一致,那么这种重排序合法。
- Happens-before原则规则
- 程序次序原则:一个线程内,按照代码顺序,书写在前面的操作先行发生于书写在后面的操作
- 锁定原则:一个unLock操作先行发生于后面对同一个锁的lock操作
- volatile变量规则:对一个变量的写操作先行发生于后面对这个变量的读操作
- 传递规则:A>B且B>C,那么A>C
- 线程启动规则:Thread对象的start()方法先行发生于此线程的每个动作
- 线程终端规则:对线程的interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生
- 线程终结规则:线程中所有的操作都先行发生于线程的终止检测
- 对象终结规则:一个对象的舒适化完成先行发生他的finalize()方法的开始
- Java对象头
- 偏向锁:大多数情况下,锁不仅不存在多线程竞争,而且总是由同一线程多次获得,为了让线程获得锁的代价更低而引入了偏向锁。
- 轻量级锁:线程在执行同步块之前,JVM会先在当前线程的栈帧中创建用于存储锁记录的空间,并将对象头中的Mark Word赋值到锁记录中,然后线程尝试使用CAS将对象头中的Mark Word替换为指向锁记录的指针。
- synchronized原理分析
- 代码块同步时,使用monitorenter和monitorexit指令实现,方法同步则是依赖方法修饰符ACC_SYNCHRONIZED来完成
- monitorenter指令是在编译后插入到同步代码块的开始位置,而monitorexit是插入到方法结束和异常处
网友评论