Java并发之volatile,synchronized

不做任何处理的并发操作带来的问题:

程序中的线程是并发执行的,并发执行的过程中由于操作不是原子性的原因,会导致变量不可见的现象,导致最后的预期结果跟实际结果存在差异。

volatile语义:

(1)在处理器处理volatile变量之后,会将数据立即写入到内存中。

(2)在写入操作执行之后,会导致其他缓存了该变量的处理器的缓存失效,从而在需要操作的时候,从新加载内存中的数据到自己的缓存中,来保障数据的可见性。

(3)volatile变量不被保证是原子操作,但是是内存可见的。

volatile实现的原理:

    volatile变量在执行时,会增加一个lock指令,该lock指令就导致了上述语义的产生。同时在多处理器的情况下,使用内存一致性原则。来保证不能对同时在多个处理器中缓存中缓存了的数据进行写操作。从而保证数据的一致性。

synchronized:

        synchronized是实现java并发编程的重要字段,且java中的每个对象都可以作为synchronized的锁。

        synchronized的同步用在下面的几种场合:

    (1)同步方法,此时的锁对象就是该类的对象实例

    (2)静态同步代码块,此时的锁的对象的就是类本身

    (3)同步代码块,此时是synchronized中的对象

synchronized的原理:

        synchronized的代码块是编译阶段会在代码的开始阶段插入monitorenter指令,会在代码的结束时插入monitorexit指令,线程在进入同步代码块时,会检查对象的对象头中是否有monitor标记,若存在,则进入同步代码快,获取到对象的锁,其他的线程则处于阻塞状态。

synchronized多数人称之为重量级的锁,因为在线程得到对象锁时候,其他的线程就会被阻塞,直到被唤醒重新进行锁的争夺,导致系统的响应时间变慢。

锁的四种状态:

无锁状态,偏向锁,轻量锁,重量锁。

偏向锁(适合单一线程执行同步方法):

        大多数情况下,线程之间不存在锁的争夺,而且很多时候是同一线程一直拥有着某个锁,为了减少锁得开销,而出现了偏向锁。线程在需要锁的时候,首先会检查,对象的头中是否保存有指向该线程的指针,若存在,则证明,该线程拥有锁,否则检查偏向锁的标记是否为一,若不是1,则使用CAS算法来争夺偏向锁。

        偏向锁的释放是在有争夺的情况下进行的,偏向锁的释放时,需要在全局安全点的情况下,暂停所有的线程,若检测拥有偏向锁的线程死亡,那么将对象的头设置为无锁的状态,或者重新标记锁的状态。

轻量锁:

    获得轻量锁的时候,线程需要开辟空间来容纳锁的标记位,会首先将对象的mark word复制到该空间中,之后使用CAS算法,将对象头中的markword替换为指向锁记录的指针,若成功,那么获得锁,否则,自旋来获取锁。

    释放轻量锁的时候,若成功将display markword替换会对象的头,那么释放锁成功,否则说明锁存在竞争,将锁膨胀为重量级锁,其他线程阻塞,轻量锁释放之后,唤醒阻塞的线程,开始锁的争夺。

猜你喜欢

转载自blog.csdn.net/qq_32182461/article/details/80290366
今日推荐