前言在我们写程序的过程中,总会听到或接触到很多的锁,比如什么:进程锁、线程锁、乐观锁、悲观锁、独占锁、共享锁、排它锁、意向锁、分布式锁、自旋锁、互斥锁等等,这些是怎么回事呢?怎么区分呢??应用场景有哪些呢???
定义最好的区别就是从定义去区分,首先也应该从定义去着手:
-
进程锁和线程锁 :貌似没有进程锁和线程锁的完整定义,如有,再补充,有一个进程互斥锁和线程互斥锁的区别:
假设整条道路看作【进程】
道路的车道看作【线程】
一些线程(车道)共享进程(道路)公共资源(土地资源);
一些线程(车道)必须依赖于进程(道路),说线程能脱离于进程存(像离道路车道没意义);
一些线程(车道)间并发执行(各车道走我走我)、互相同步(某些车道交通灯亮禁止继续前行或转弯必须等待其车道车辆通行完毕);
一些线程(车道)间依靠代码逻辑(交通灯)控制运行,但代码逻辑控制误(死锁线程同竞争唯资源)线程陷入混乱序
一些线程(车道)间谁先运行,未知线程刚配CPU后片(交通灯变化)刻才能知道
应用场景:一般都用在操作系统里面的。 -
乐观锁(Optimistic Lock) :顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库如果提供类似于write_condition机制的其实都是提供的乐观锁;
-
悲观锁(Pessimistic Lock):顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁;
应用场景:数据库或者是对数据的操作方面;
两种锁各有优缺点,不可认为一种好于另一种,像乐观锁适用于写比较少的情况下,即冲突真的很少发生的时候,这样可以省去了锁的开销,加大了系统的整个吞吐量。但如果经常产生冲突,上层应用会不断的进行retry,这样反倒是降低了性能,所以这种情况下用悲观锁就比较合适。 -
独占锁 :文件锁定有两种方式:共享的和独占的。多个共享锁可同时对同一文件区域发生作用;独占锁则不同,它要求其他区域不能有其他锁定再起作用。
- 共享锁 :又称读锁(S锁)是读取操作创建的锁。其他用户可以并发读取数据,但任何事务都不能对数据进行修改(获取数据上的排他锁),直到已释放所有共享锁,这是最广泛的定义;在MySQL中的InnoDB引擎实现的行锁中定义的共享锁是:允许一个事务去读一行,阻止其他事务获得相同数据集的排它锁;
- 排它锁 :又称写锁(X锁)如果事务T对数据A加上排他锁后,则其他事务不能再对A加任任何类型的锁,直到在事务的末尾将资源上的锁释放为止。获准排他锁的事务既能读数据,又能修改数据;在MySQL的InnoDB引擎实现的行锁中定义的排它锁是:允许获得排它锁的事物更新数据,阻止其他事物取得相同数据集的共享读锁和排它写锁;
- 为了允许行锁和表锁共存,实现多粒度锁机制,InnoDB还有两种内部使用的意向(Intention Locks),这两种意向锁都是表锁;
-
意向锁:又分为意向共享锁(IS)和意向排它锁(IX):意向共享锁:事务打算给数据行加行共享锁,事务在给一个数据行加共享锁必须先取的该表的IS锁;意向排它锁:事务打算给数据行加行排它锁,事务在给一个数据行加排它锁前必须先取的该表的IX锁;
应用场景:数据库或数据方面,比如MySQL的锁机制;
-
自旋锁:是专为防止多处理器并发而引入的一种锁,它在内核中大量应用于中断处理等部分;与互斥锁有点类似,只是自旋锁不会引起调用者睡眠,如果自旋锁已经被别的执行单元保持,调用者就一直循环在那里看是 否该自旋锁的保持者已经释放了锁,”自旋”一词就是因此而得名。其作用是为了解决某项资源的互斥使用。因为自旋锁不会引起调用者睡眠,所以自旋锁的效率远 高于互斥锁。虽然它的效率比互斥锁高,但是它也有些不足之处:
1、自旋锁一直占用CPU,他在未获得锁的情况下,一直运行--自旋,所以占用着CPU,如果不能在很短的时 间内获得锁,这无疑会使CPU效率降低。
2、在用自旋锁时有可能造成死锁,当递归调用时有可能造成死锁,调用有些其他函数也可能造成死锁,如 copy_to_user()、copy_from_user()、kmalloc()等。
因此我们要慎重使用自旋锁,自旋锁只有在内核可抢占式或SMP的情况下才真正需要,在单CPU且不可抢占式的内核下,自旋锁的操作为空操作。自旋锁适用于锁使用者保持锁时间比较短的情况下。。 -
互斥锁:最常使用于线程同步的锁;标记用来保证在任一时刻,只能有一个线程访问该对象,同一线程多次加锁操作会造成死锁;临界区和互斥量都可用来实现此锁,通常情况下锁操作失败会将该线程睡眠等待锁释放时被唤醒;
应用场景:多是在操作系统方面。
-
分布式锁:是控制分布式系统之间同步访问共享资源的一种方式。在分布式系统中,常常需要协调他们的动作。如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要互斥来防止彼此干扰来保证一致性,在这种情况下,便需要使用到分布式锁。
应用场景:分布式系统
小结:从以上的用途和应用场景等分析可知,很多锁都是成对出现的,例如:乐观锁和悲观锁、共享锁和排它锁、进程锁和线程锁,在某一领域或者范围内可能还会引申到其他的范畴当中,比如在MySQL中的锁就会跟事务和数据库引擎绑在一起;而且很多锁都用在数据库、操作系统方面,因为锁问题归根到底也是为了解决并发问题,并发就是多个进程或者线程同时访问某一资源。