synchronized 底层的锁(偏向锁,无锁,轻量级锁,重量级锁)

目录

synchronized地层锁的分类:

一、偏向锁

 1、怎么理解偏向锁呢?

 2.设置偏向锁的延迟参数

二、无锁

1、什么是无锁状态?

三、轻量级锁

1、获取轻量级锁的两种情况:

四、重量级锁

1、成为重量级锁的两种情况:

          五、程序演示各种锁

                 1、没有开启偏向锁的无锁,轻量级锁,重量级锁的代码演示

                  2、开启偏向锁代码演示


synchronized地层锁的分类:

一、偏向锁

         其实在大部分情况下,锁不仅仅不存在多线程竞争,而且总是由同一个线程多次获得,  为了线程获取锁的代价更低就引入了偏向锁的概念。

1.怎么理解偏向锁呢?

        当一个线程访问了同步锁的代码块时,会在对象头中存储当前线程的ID,后续这个线程进入和退出这段加了同步锁的代码块时,不需要再次加锁和释放锁。 而是直接比较对象里面是否存储了指向当前线程的偏向锁。 如果相当表示偏向锁是指向当前线程的,就不需要要再次尝试获得锁。

 2.设置偏向锁的延迟参数

         一般偏向锁的启动有一个延迟,可以通过命令设置延迟为0.

         修改偏向锁的延迟时间的参数:-XX:BiasedLockingStartupDelay=0

         关闭指针压缩: -XX:-UseCompressedOops        

          那在对一个 Object 做 synchronized 的时候,会立即上一把偏向锁。当处于偏向锁状态时,markwork 会记录当前线程 ID。

二、无锁

1、什么是无锁状态?

       无锁是指没有对资源进行锁定,所有的线程都能访问并修改同一个资源,但同时只有一个线程能修改成功。无锁的特点是修改操作会在循环内进行,线程会不断的尝试修改共享资源。如果没有冲突就修改成功并退出,否则就会继续循环尝试。如果有多个线程修改同一个值,必定会有一个线程能修改成功,而其他修改失败的线程会不断重试直到修改成功。
 

三、轻量级锁

      轻量级锁是指当锁是偏向锁的时候,却被另外的线程所访问,此时偏向锁就会升级为轻量级锁,其他线程会通过自旋的形式尝试获取锁,线程不会阻塞,从而提高性能。

1、获取轻量级锁的两种情况:

       一是没有开启偏向锁功能时:只有一个线程去获得锁对象时,这时就是轻量级锁状态。
       二是开启偏向锁功能之后,由于多个线程竞争偏向锁导致偏向锁升级为轻量级锁。
一旦有第二个线程加入锁竞争,偏向锁就升级为轻量级锁(自旋锁)。这里要明确一下什么是
锁竞争:如果多个线程轮流获取一个锁,但是每次获取锁的时候都很顺利,没有发生阻塞,那么就不存在锁竞争。只有当某线程尝试获取锁的时候,发现该锁已经被占用,只能等待其释放,这才发生了锁竞争。
       在轻量级锁状态下继续锁竞争,没有抢到锁的线程将自旋,即不停地循环判断锁是否能够被成功获取。获取锁的操作,其实就是通过CAS修改对象头里的锁标志位。先比较当前锁标志位是否为“释放”,如果是则将其设置为“锁定”,比较并设置是原子性发生的。这就算抢到锁了,然后线程将当前锁的持有者信息修改为自己的。但是长时间的自旋操作是非常消耗资源的,一个线程持有锁,其他线程就只能在原地空耗CPU,执行不了任何有效的任务,这种现象叫做忙等(busy-waiting)。如果多个线程用一个锁,但是没有发生锁竞争,或者发生了很轻微的锁竞争,那么synchronized就用轻量级锁,允许短时间的忙等现象。这是一种折衷的想法,短时间的忙等,换取线程在用户态和内核态之间切换的开销。
 

四、重量级锁

1、成为重量级锁的两种情况:

      没有开启偏向锁:当一个线程还没有释放锁对象,有一个线程来获取锁对象,此时该锁就会因为锁竞争锁对象二升级为重量级锁。

       开启偏向锁后:一个锁对象被一个线程作为锁对象,还没有释放锁对象,其他的线程也要获取该锁对象。

       注意升级到重量级锁。如果锁竞争加剧(如线程自旋次数或者自旋的线程数超过某阈值,JDK1.6 之后,由 JVM 自己控制改规则),就会升级为重量级锁。此时就会向操作系统申请资源,线程挂起,进入到操作系统内核态的等待队列中,等待操作系统调度,然后映射回用户态。在重量级锁中,由于需要做内核态到用户态的转换,而这个过程中需要消耗较多时间,也就是“重”的原因之一。

        Synchronized 的重量级锁是通过对象内部的一个叫做监视器锁(monitor)来实现的,监视器锁本质又是依赖于底层的操作系统的 Mutex Lock(互斥锁) 来实现的。而操作系统实现线程之间的切换需要从用户态转换到核心态,这个成本非常高,状态之间的转换需要相对比较长的时间,这就是为什么 Synchronized 效率低的原因。因此,这种依赖于操作系统 Mutex Lock 所实现的锁称之为“重量级锁”。

五、程序演示各种锁

   1、没有开启偏向锁的无锁,轻量级锁,重量级锁的代码演示

ackage com.shang.demo02.没有偏向轻量级锁重量级锁无锁;

import org.openjdk.jol.info.ClassLayout;

public class test01 {

	public static void main(String[] args) throws InterruptedException {
		A a=new A();
		//ClassLayout ai= ClassLayout.parseInstance(obj);
		
		String str= ClassLayout.parseInstance(a).toPrintable();
		System.out.println(str);
		
		new Thread() {
			@Override
			public void run() {
				synchronized(a) {
					try {
						Thread.sleep(500);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				
				System.out.println(Thread.currentThread().getName());
			}
		}.start();
		Thread.sleep(10);
		str= ClassLayout.parseInstance(a).toPrintable();
		System.out.println(str);//轻量级锁
		new Thread() {
			@Override
			public void run() {
				synchronized(a) {
					try {
						Thread.sleep(500);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				
				System.out.println(Thread.currentThread().getName());
			}
		}.start();
		Thread.sleep(10);
		str= ClassLayout.parseInstance(a).toPrintable();
		System.out.println(str);//重量级锁
	}

}

结果显示:

2、开启偏向锁代码演示

package com.shang.demo.偏向锁;

import org.openjdk.jol.info.ClassLayout;

public class test03 {

	public static void main(String[] args) throws InterruptedException {
		A a=new A();
		new Thread() {
			@Override
			public void run() {
				synchronized(a) {
					try {
						Thread.sleep(500);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				/*
				 * 显示的让当前线程不结束,如果结束了,下一个线程的id和感刚刚这个线程的id是一样的。
				*/
				try {
					Thread.sleep(1000000);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}.start();
		Thread.sleep(100);
		String str=ClassLayout.parseInstance(a).toPrintable();
		System.out.println(str);//101无锁可偏向
		Thread.sleep(1000);//保证上一个线程已经把任务执行结束了
		new Thread() {
			@Override
			public void run() {
				synchronized(a) {
					try {
						Thread.sleep(500);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				
			}
		}.start();
		Thread.sleep(100);
		 str=ClassLayout.parseInstance(a).toPrintable();
		System.out.println(str);
		}

}

结果显示:

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值