java的锁

java的锁

一、锁的类型

数据库的锁相关:读锁、写锁、表锁、行锁

1.1存储引擎:

​ InnoDB :支持主外键,行锁,只锁住某一行;不仅缓存索引还缓存真实数据,对内存要求高,内存大小对性能有影响;关注的是事务

​ MyISAM:不支持主外键;表锁,即使操作一条记录会锁住整个表;只缓存索引,不缓存真实数;关注的是性能。

1.2锁分类

锁分类:分为读锁(共享锁、Share Locks 简称S锁)、写锁(独占锁、Exclusive Locks简称X锁)

读锁:事务A对对象T加S锁,其他事务也只能对T加S锁。多个事务可以同花读,但不能有写操作。知道A释放S锁

写锁:事务A对对象T加X锁后,其他事务不能对T加任何锁。

手动加表上的表锁

lock table 表名 read(/write),表名 read (/write);

查看表上加过的锁

show open tables;

释放表锁

unlock tables

如何分析表锁定———表锁的查看
show status  like 'table%';Table_locks_immediate;

表示产生表级锁定的次数,表示可以立即获取锁的查询次数,每次加1; Table_locks_waited
表示出现表级锁定争用而发生等待的次数(不能立即获取锁的次数,每等待一次锁加1),此值很高说明存在着较严重的表级锁争用情况。

1.2.1 行锁

​ 定义:行锁是建立在索引上的锁。如果没有索引,那么行锁就会自动锁全表,那就是表锁了。

​ 注意:两个事务不能锁同一个索引;行锁会发生死锁,发生锁冲突几率低,并发高。

行锁分为读锁和写锁

行锁就是对一行或者多行进行加锁,比如

#对某一行进行加锁
begin;
select * from tableA where id="9" for update;
commit;
1.2.1.1间隙锁

当我们用范围条件而不是相等条件检索数据并请求共享或排他锁时,InnoDB会给复合条件的已有数据记录的索引项添加锁;对于键值在条件范围内但并不存在的记录,叫做“间隙”;InnoDB会对这个“间隙”也加锁。这种锁叫间隙锁。

#行锁的查看
select status like 'innodb_row_lock%';
#会出现的结果
Innodb_row_lock_current_waits:当前正在等到锁定的数量
Innodb_row_lock_time:从系统启动到现在锁定总时间的长度
Innodb_row_lock_time_avg:每次等待所花平均时间
Innodb_row_lock_time_max:从系统启动到现在等待最常的一次所花的时间
Innodb_row_lock_waits:系统启动后到现在总共等待的次数
重要的参数:等待总次数、等待总时长、等待平均时长。
1.2.1.2优化建议
  • 尽量让所有的数据检索都通过索引来完成,避免无索引导师行锁升级为表锁
  • 合理设计索引,尽量缩小锁的范围
  • 尽可能的减少索引条件,避免间隙锁
  • 尽量控制事务的大小,减少锁定资源量和时间长度
  • 尽可能低级别的事务隔离
1.2.1.3死锁
  • 不同表 相同记录 行锁冲突
  • 相同表记录行锁冲突:事务A处理[1,2,3,4]事务B处理[3,5,6,8]
  • 不同索引冲突:这种情况比较隐晦,事务A在执行时,除了在二级索引加锁外,还会在聚簇索引上加锁,在聚簇索引上加锁的顺序是[1,4,2,3,5],而事务B执行时,只在聚簇索引上加锁,加锁顺序是[1,2,3,4,5],这样就造成了死锁的可能性。
1.2.1.4行锁之手动加锁
  • 共享锁(读锁):select * from table_name where … lock in share mode
  • 排它锁(写锁): select * from table_name where … for update
    • 注:serviceImple层:使用for update 一定要在方法上加上@Transactional(isolation = Isolation.READ_COMMITTED),当事务处理完后,for update 才会将行级锁解除。

img

1.2.2 表锁

​ 定义:对整个表进行加锁。

#手动加表锁
lock table 表名 read(/write),表名 read (/write);
#查询表锁
show open tables;查询表上加过的锁

show status  like 'table%';Table_locks_immediate;
#释放表锁
unlock tables;

二、悲观锁

总是假设最坏的情况,每次去拿数据的时候,都认为别人会修改。

所以>>> 每次拿数据的时候都会加锁,这样别人想拿这个数据的时候都会上锁。传统的关系型数据库中就用到了很多这种锁机制;比如行锁,表锁,读写锁。都是在操作之前先上锁。

java中的 ___synchronized___和___ReentrantLock___等独占锁就是悲观锁思想的实现

  • synchronized:同步锁。保证在同一时刻,被修饰的代码块或方法只能有一个线程执行。保证安全。java解决并发问题的一种方法。
  • ReentrantLock:和synchronized差不多

三、乐观锁

​ 总是假设最好的情况,每次拿数据的时候,都认为别人不会修改,所以不会上锁 。但是在更新数据的时候会查看一下别人有没有更新这个数据。可以使用版本号机制和CAS算法实现。

​ 适用于多读的类型。这样可以提高吞吐量。

像数据库提供的类似于write_condition机制,其实都是提供的乐观锁。在Java中java.util.concurrent.atomic包下面的原子变量类就是使用了乐观锁的一种实现方式CAS实现的。

四、两种锁额常用场景

  • 乐观锁:乐观锁适用于写比较少的情况下**(多读场景),**即冲突真的很少发生的时候,这样可以省去了锁的开销,加大了系统的整个吞吐量
  • 悲观锁:**多写的情况,**一般会经常产生冲突,这就会导致上层应用会不断的进行retry,这样反倒是降低了性能,所以一般多写的场景下用悲观锁就比较合适。

五、两种锁的实现机制

### 5.1乐观锁:(版本号机制和CAS机制) 

#### 5.1.1版本号机制

一般在数据表中加一个数据版本号version字段,表示数据被修改的次数。当数据被修改后,version加一。在事务A要更新数据的时候,读取数据的同时,也会读取version,在提交更新时,若事务A刚才读取到的值与之前读取到的version相同才更新。否则重试更新操作。

5.1.2CAS 算法(compare and swap)比较与交换

注:没有锁。

目的:在不使用锁的情况下实现进程的同步。也就是在没有线程被阻塞的情况下实现变量的同步。也叫做非阻塞同步(No-blocked-synchronization)

CAS设计三个操作数

  • 需要读写的内存值 V
  • 进行比较的值 A
  • 拟写入的新值 B

当且仅当 V 的值等于 A时,CAS通过原子方式用新值B来更新V的值,否则不会执行任何操作(比较和替换是一个原子操作)。一般情况下是一个自旋操作,即不断的重试。

5.1.3乐观锁的缺点
  • ABA问题 :一开始是A,更新成了B,后来又更新成了A。JDK 1.5 以后的 AtomicStampedReference 类就提供了此种能力,其中的 compareAndSet 方法就是首先检查当前引用是否等于预期引用,并且当前标志是否等于预期标志,如果全部相等,则以原子方式将该引用和该标志的值设置为给定的更新值。
  • 循环时间开销大:自旋CAS(也就是不成功就一直循环执行直到成功)如果长时间不成功,会给CPU带来非常大的执行开销。 如果JVM能支持处理器提供的pause指令那么效率会有一定的提升,pause指令有两个作用,第一它可以延迟流水线执行指令(de-pipeline),使CPU不会消耗过多的执行资源,延迟的时间取决于具体实现的版本,在一些处理器上延迟时间是零。第二它可以避免在退出循环的时候因内存顺序冲突(memory order violation)而引起CPU流水线被清空(CPU pipeline flush),从而提高CPU的执行效率。
  • 只能保证一个共享变量的原子操作:CAS 只对单个共享变量有效,当操作涉及跨多个共享变量时 CAS 无效。 JDK 1.5开始,提供了AtomicReference类来保证引用对象之间的原子性,你可以**把多个变量放在一个对象里来进行 CAS 操作.**所以我们可以使用锁或者利用AtomicReference类把多个共享变量合并成一个共享变量来操作。

六、CAS与synchronized的使用场景

6.1 资源竞争少的(线程冲突较轻)

​ 使用CAS方法较好。CAS基于硬件实现,不需要进入内核,不需要切换线程。性能更高

6.2资源竞争严重的(线程冲突严重)

使用synchronized较好。CAS的自旋概率较大。时间浪费。

自旋锁:https://blog.csdn.net/qq_34337272/article/details/81252853

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值