Java多线程-锁

目录

锁有哪些种类

乐观锁和被悲观锁

实现乐观锁的两种常见方式

自旋锁

互斥锁/读写锁

独享锁/共享锁

不可重入/重入锁

公平锁/非公平锁

分段锁

可中断锁

synchronized同步锁

锁有哪些种类

  • 乐观锁/悲观锁(乐观锁与悲观锁并不是特指某两种类型的锁,是人们定义出来的概念或思想)

  • 独享锁/共享锁

  • 互斥锁/读写锁

  • 不可重入锁/可重入锁

  • 公平锁/非公平锁

  • 分段锁(一种锁的设计,并不是具体的一种锁)

  • synchronized同步锁(无锁/偏向锁/轻量级锁/重量级锁)

  • 自旋锁

  • 可中断锁

乐观锁和被悲观锁

乐观锁与悲观锁并不是特指某两种类型的锁,是人们定义出来的概念或思想,主要是指看待并发同步的角度。

乐观锁认为自己在使用数据的时候不会有其他的线程修改数据,所以不会添加锁,只是在更新数据的时候去判断之前有没有别的线程更新了这个数据

锁实现:CAS算法

使用场景:读操作较多,不加锁的特点能够使其读操作的性能大幅提升

悲观锁认为自己在使用数据的时候,一定有别的线程来修改数据,在获取数据的时候会先加锁,确保数据不会被别的线程修改。

锁实现:关键字synchronized、接口Lock的实现类

使用的场景:写操作较多,先加锁可以保证写操作是数据正确

实现乐观锁的两种常见方式

(1)数据版本机制

一般是在数据表中加上一个数据版本号version字段,表示数据被修改的次数,当数据被修改时,version值会加一。当线程A要更新数据值时,在读取数据的同时也会读取version值,在提交更新时,若刚才读取到的version值为当前数据库中的version值相等时才更新,否则重试更新操作,直到更新成功。
(2)CAS算法

即compare and swap,是一种有名的无锁算法。就是在没有线程被阻塞的情况下实现变量的同步,所以也叫非阻塞同步。
1、需要读写的内存值 V
2、进行比较的值 A
3、拟写入的新值 B
当且仅当 V 的值等于 A时,CAS通过原子方式用新值B来更新V的值,否则不会执行任何操作。一般情况下是一个自旋操作,即不断的重试。

自旋锁

自旋是指当一个线程在获取锁的时候,如果锁已经被其他线程获取,那么该线程将循环等待,然后不断判断是否能够被成功获取,自旋直到获取到锁才会退出循环。自旋是通过CAS算法进行的。

自旋锁是当前线程在获取锁时,如果发现锁已经被其他线程占有,它不马上阻塞自己,在不放弃CPU使用权的情况下,多次尝试获取(默认次数是10,可以使用-XX:PreBlockSpinsh参数设置该值),很有可能在后面几次尝试中其他线程已经释放了锁。如果尝试指定的次数后仍没有获取到锁则当前线程才会被阻塞挂起。

好处是减少线程上下文切换的消耗,缺点是循环会消耗CPU。

互斥锁/读写锁

互斥锁/读写锁是独享锁/共享锁具体的实现

互斥锁在Java中的具体实现就是ReentrantLock。

读写锁在Java中的具体实现就是ReadWriteLock:对资源读取和写入的时候拆分为两部分处理,读的时候可以多线程一起读,写的时候必须同步地写

独享锁/共享锁

独享锁是指该锁一次只能被一个线程所持有

共享锁是指该锁可被多个线程所持有

不可重入/重入锁

可重入锁又名递归锁,是指在同一个线程在外层方法获取锁的时候,在进入内层方法会自动获取锁。也就是在执行对象中所有同步方法不用再次获得锁 。

示例:

synchronized void setA() throws Exception{
  Thread.sleep(1000);
  setB();
}
 
synchronized void setB() throws Exception{
  Thread.sleep(1000);
}

公平锁/非公平锁

公平锁是指多个线程按照申请锁的顺序来获取锁:按等待获取锁的线程的等待时间进行获取,等待时间长的具有优先获取锁权利

非公平锁是指多个线程获取锁的顺序并不是按照申请锁的顺序,有可能后申请的线程比先申请的线程优先获取锁。有可能,会造成优先级反转或者饥饿现象。

分段锁

分段锁其实是一种锁的设计,并不是具体的一种锁,对于ConcurrentHashMap而言,其并发的实现就是通过分段锁的形式来实现高效的并发操作。

可中断锁

在等待获取锁过程中可中断   

synchronized同步锁

锁有四种级别,按照量级从轻到重分为:无锁、偏向锁、轻量级锁、重量级锁。

锁只能升级不能降级

偏向锁:是指一段同步代码一直被一个线程所访问,那么该线程会自动获取锁。降低获取锁的代价。

在一段时间内,锁不存在多线程竞争, 而是总是由同一个线程多次获得,为了让线程获取锁的代价更低就引入了偏向锁的概念。怎么理解偏向锁呢? 当一个线程访问加了同步锁的代码块时,会在对象头中存储当前线程的 ID,后续这个线程进入和退出这段加了同步锁的代码块时,不需要再次加锁和释放锁。而是直接比较对象头里面是否存储了指向当前线程的偏向锁。如果相等表示偏向锁是偏向于当前线程的,就不需要再尝试获得锁了。
轻量级锁:是指当锁是偏向锁的时候,被另一个线程所访问,偏向锁就会升级为轻量级锁,其他线程会通过自旋的形式尝试获取锁,不会阻塞,提高性能。

重量级锁:是指当锁为轻量级锁的时候,另一个线程虽然是自旋,但自旋不会一直持续下去,当自旋一定次数的时候,还没有获取到锁,就会进入阻塞,该锁膨胀为重量级锁。重量级锁会让他申请的线程进入阻塞,性能降低。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值