认识一下synchronized锁

什么是锁?

计算机科学中,为了保证多线程情况下对共享资源操作的安全性,对资源操作时需实现一种同步的机制来对其进行限制,所以在编程中引入了锁的概念,来保证数据操作的完整性。在java中,每个对象都对应于一个可称为"互斥锁"的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。
无论是任何场景,只要有可能存在多线程竞争,那么必然会加锁来保证安全。所以说并不是一定存在竞争才会加锁,是为了防止出现竞争而加锁。
一个优秀的项目,绝大部分情况下都要使用多线程的技术来提升CPU的利用率,所以说多线程并发编程是优秀开发人员必须要掌握的技术。

Java中的锁

Java中用到锁的情况,常用的有两种,一种是用synchronized加锁,另一种是采用ReentrantLock,两者各有其优势,更重要的是根据不同的场景去进行使用

Synchronized

synchronized在JDK1.6以前是重量级锁,什么是重量级锁呢?
所谓重量级锁是相对来说的,加锁本身都是需要一个过程来实现的,而JDK1.5时,synchronized是需要通过操作系统自身的互斥量(mutex lock)来实现,然而这种实现方式需要通过用户态内核态的切换来实现,切换的过程就会带来很大的开销,但正如上面所说,加锁是为了防止竞争,有可能并不会出现这种竞争,那么就没有必要去都采用重量级的方式加锁,从而开发者在加锁的过程中做了一些优化

PS:用户态是操作在JVM本身执行,内核态是操作经过了操作系统

锁的升级过程

锁的4种状态(膨胀过程):无锁 ➡ 偏向锁 ➡ 轻量级锁 ➡ 重量级锁

无锁

无锁,顾名思义,就是没有锁。没有加锁和解锁的过程,可以理解为只是一个概念性的意义。Java中每一个被new出来的对象,都是无锁态(锁标识:001),此时的对象是一个无瑕疵的对象,正如初生婴儿,来到这个美好的世界

偏向锁

偏向锁,顾名思义,就是这个对象锁带有偏向的概念,那么何为偏向呢?假如你有一个苹果,现在有两个人,一个是认识很久的同学,一个是陌生的同学,那么必须分给一个人的话,你会偏向分给谁?相信大多数同学都会偏向于熟悉的人。那么加锁也是,假如一个线程给对象加过锁之后(CAS加锁,将自己的ThreadID放到MarkWord的相应位置),那么对象头中会留存该线程的ThreadID,同时修改锁标识(101),后续如果还是这个ThreadID来加锁,就无需CAS了,只需要比较一下,没有了交换的过程,能少走一步就优化一点。像平时用的StringBuffer,也是用的synchronizd加锁,为什么它安全而高效呢,就是因为多数情况下大量的加锁解锁过程都是一个线程来重复操作的,那么既然重复,我们就需要做出优化,即出现了偏向锁
在这里插入图片描述

轻量级锁

所谓轻量级锁,显而易见,是相对于重量级锁来说的,轻量级锁是多个线程访问时,线程不会阻塞。
从锁升级的角度来说,当一个对象被A线程上锁解锁后,对象的对象头中会存放线程的ThreadID,记录对象偏向与哪一个线程,那么此时对象就偏向于A线程,但是后来B线程也来给对象进行上锁,那么此时通过CAS去比较对象头中的ThreadID,发现存放的ThreadID不是当前线程的ID,那么就撤销偏向锁,将对象升级为轻量级锁。
也就是说轻量级锁只是通过CAS比较并交换ThreadID来进行加锁的操作,没有发生用户态与内核态的切换,同时也没发生线程之间的阻塞、唤醒等操作

重量级锁

重量级锁是充分调用操作系统来进行加锁操作,在Java中,多线程发生资源竞争激烈时,才会将锁升级为重量级锁,只有重量级锁是需要用户态和内核态进行切换(也就是Java的内存与操作系统的内存之间发生调用),此操作是较为耗时的,所以称之为重量级锁

Synchronized的用法

  • 修饰一个方法,对方法进行同步
  • 修饰静态方法,静态方法的同步
  • 修饰代码块,synchronized(this){}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值