自旋锁
是指当一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,直到获取到锁才会退出循环。
如果别的线程长期持有该锁,那么你这个线程就一直在 while while while 地检查是否能够加锁,浪费 CPU 做无用功。
适用场景:冲突不多,等待时间不长的情况下,或者少次数的尝试自旋。
互斥锁
操作系统负责线程调度,为了实现「锁的状态发生改变时再唤醒」就需要把锁也交给操作系统管理。所以互斥器的加锁操作通常都需要涉及到上下文切换,操作花销也就会比自旋锁要大。
适用场景:绝大部分情况下都可以直接使用互斥锁。
条件锁
它解决的问题不是「互斥」,而是「等待」。
消息队列的消费者程序,在队列为空的时候休息,数据不为空的时候(条件改变)启动消费任务。条件锁的业务针对性更强。
读写锁
内部有两个锁,一个是读的锁,一个是写的锁。
如果只有一个读、一个写,那么等价于直接使用互斥锁。
不过由于读写锁需要额外记录读数量,花销要大一点。
也可以认为读写锁是针对某种特定情景(读多写少)的「优化」。
适用场景:读多写少,而且读的过程时间较长,可以通过读写锁,减少读冲突时的等待。
悲观锁
认为每次对数据库的操作(查询、修改)都是不安全的,因此每次操作都会把这条数据锁掉,直到本次操作完毕释放该锁。
适用场景:就是在对某个数据在处理的过程中,不允许其他人或程序或线程修改此数据,从而保证了数据修改的独占和排他性。通常大多数的悲观锁都是通过数据库的锁机制来实现的,比如:
select * from table where id = ‘xxx’ for update;
缺点:悲观锁因为独占和排他的特点,导致只有在事务提交以后才能被其他人(或程序或线程)修改。可想而知,如果并发量很大,将会导致应用程序在数据库处理层面阻塞而变得十分缓慢,并发量严重降低。
乐观锁
查询数据的时候总是认为是安全的,不会锁数据;等到更新数据的时候会判断这个数据是否被人修改过,如果有人修改过了则本次修改失败。
每个人(或程序或线程)都可以去读取并修改这个数据,但是在修改完成后,对提交才做限制,只有满足一定条件的数据才可以被修改(提交)。乐观锁的实现,一般大家通过对数据库表加一个version字段,当对某条记录修改后,同时对version(old)+1,然后把看version(new)的值是否大于数据库当前version(DB)的值,如果大于则提交,否则说明其他人(或程序或线程)已经修改过本条数据(version是old),只能继续读取数据库最新的数据重复之前的操作。
update table set name=’xxx’ ,version = version(old)+1 where version = version(old) and id=’xxxxxx’;
比如这个sql,如果返回大于1说明数据被更新了,则说明数据从读取出来后就没有被其他人(或程序或线程)修改过,否则如果返回0,则说明,数据已经被修改。
缺点:当数据的修改操作发生的比较频繁,乐观锁的效率就会很低,因为每次读取后更新将基本上都不成功。
分布式锁
为了防止分布式系统中的多个进程之间相互干扰,大家需要一种分布式协调技术来对这些进程进行调度。而这个分布式协调技术的核心就是来实现这个分布式锁。
分布式锁应该具备以下条件:
1、分布式系统环境下,一个方法在同一时间只能被一个机器的一个线程调用;
2、高可用的获取锁与释放锁;
3、高性能的获取锁与释放锁;
4、具备可重入特性;
5、具备锁失效机制,防止死锁;
6、具备非阻塞锁特性,即没有获取到锁将直接返回获取锁失败。
分布式锁的实现方法:
Memcached:利用 Memcached 的add命令。此命令是原子性操作,只有在key不存在的情况下,才能add成功,也就意味着线程得到了锁。
Redis:和 Memcached 的方式类似,利用 Redis 的setnx命令。此命令同样是原子性操作,只有在key不存在的情况下,才能set成功。
Zookeeper:利用 Zookeeper 的顺序临时节点,来实现分布式锁和等待队列。Zookeeper 设计的初衷,就是为了实现分布式锁服务的。
Chubby:Google 公司实现的粗粒度分布式锁服务,底层利用了 Paxos 一致性算法。
共享锁
共享锁又称为读锁,简称S锁,顾名思义,共享锁就是多个事务对于同一数据可以共享一把锁,都能访问到数据,但是只能读不能修改。简单的说,就是多个事务只能读数据不能改数据。
排他锁
排他锁又称为写锁,简称X锁,顾名思义,排他锁就是不能与其他所并存,如一个事务获取了一个数据行的排他锁,其他事务就不能再获取该行的其他锁,包括共享锁和排他锁,但是获取排他锁的事务是可以对数据就行读取和修改。
排他锁指的是一个事务在一行数据加上排他锁后,其他事务不能再在其上加其他的锁。mysql InnoDB引擎默认的修改数据语句,update,delete,insert都会自动给涉及到的数据加上排他锁,select语句默认不会加任何锁类型,如果加排他锁可以使用select …for update语句,加共享锁可以使用select … lock in share mode语句。所以加过排他锁的数据行在其他事务种是不能修改数据的,也不能通过for update和lock in share mode锁的方式查询数据,但可以直接通过select …from…查询数据,因为普通查询没有任何锁机制。
偏向锁
在实际应用运行过程中发现,“锁总是同一个线程持有,很少发生竞争”,也就是说锁总是被第一个占用他的线程拥有,这个线程就是锁的偏向线程。
那么只需要在锁第一次被拥有的时候,记录下偏向线程ID。这样偏向线程就一直持有着锁,直到竞争发生才释放锁。以后每次同步,检查锁的偏向线程ID与当前线程ID是否一致,如果一致直接进入同步,退出同步也,无需每次加锁解锁都去CAS更新对象头,如果不一致意味着发生了竞争,锁已经不是总是偏向于同一个线程了,这时候需要锁膨胀为轻量级锁,才能保证线程间公平竞争锁。
centos配置mysql,ride 调用mysql odbc,mysql进程结束怎么启动,将日志写入到mysql,mysql存在语句,mysql5.7添加新用户