volatile和synchronized和Java四种锁机制

Java 支持多个线程同时访问一个对象或者对象的成员变量,由于每个线程可以拥有这个变量的拷贝(虽然对象以及成员变量分配的内存是在共享内存中的,但是每个执行的线程还是可以拥有一份拷贝,这样做的目的是加速程序的执行,这是现代多核处理器的一个显著特性),所以程序在执行过程中,一个线程看到的变量并不一定是最新的。

 关键字 volatile 可以用来修饰字段,就是告知程序任何对该变量的访问均需要从共享内存获取(读取时将本地内存置为无效,从共享内存读取),而对它的改变必须同步刷新回共享内存。保证所有线程对变量访问的可见性。


关键字 synchronized 可以修饰方法或者以同步块的形式来进行使用,它主要确保多个线程在同一个时刻,只能有一个线程处于方法或者同步块中,它保证了线程对变量访问的可见性和排他性。

java里的四种锁

synchronized 相对于 volatile 是重量了很多,因此在以前很让人诟病,但是从 JDK 1.6 版本以后为了减少获得锁和释放锁带来的性能消耗而引入了偏向锁和轻量级锁,以及锁的存储结构和升级过程

偏向锁:如果一个线程获得了锁,那么锁就进入了偏向模式。当这个线程再次请求锁时,无需再做任何同步操作
轻量级锁:轻量级锁他只是简单的将对象头部作为指针,指向持有锁的线程堆栈的内部,来判断一个线程是否持有对象锁。如果线程获得轻量级锁成功,则可以顺利进入临界区。如果轻量级锁加锁失败,则表示其他线程抢先夺到锁,那么当前线程的轻量级锁就会膨胀为重量级锁
自旋锁:轻量级锁就会膨胀为重量级锁后,虚拟机为了避免线程真实的在操作系统层面挂起,虚拟机还会在做最后的努力–自旋锁。

由于当前线程暂时无法获得锁,但是什么时候可以获得锁时一个未知数。也许在几个 CPU 时钟周期之后,就可以获得锁。如果是这样的话,直接把线程挂起肯定是一种得不偿失的选择,因此系统会在进行一次努力:他会假设在不就的将来,限额和从那个可以得到这把锁,因此虚拟机会让当前线程做几个空循环(这也就是自旋锁的意义),若经过几个空循环可以获取到锁则进入临界区,如果还是获取不到则系统会真正的挂起线程。

那么为什么锁的升级无法逆向那?

这是因为,自旋锁无法预知到底会空循环几个时钟周期,并且会很消耗 CPU,为了避免这种无用的自旋操作,一旦锁升级为重量锁,就不会再恢复到轻量级锁,这也是为什么一旦升级无法降级的原因所在。

重量级锁:等待线程唤起

猜你喜欢

转载自blog.csdn.net/u011747152/article/details/79604984