公平锁与非公平锁
公平锁
是指多个线程按照申请锁的顺序来获取锁,类似于排队买饭,先来后到,先来先服务,就是公平的,也就是队列
非公平锁
是指多个线程获取锁的顺序,并不是按照申请锁的顺序,有可能申请的线程比先申请的线程优先获取锁,在高并发环境下,有可能造成优先级翻转,或者饥饿的线程(也就是某个线程一直得不到锁),类似于允许排队加塞。。。
二者区别
公平锁:就是很公平,在并发环境中,每个线程在获取锁时会先查看此锁维护的等待队列,如果为空,或者当前线程是等待队列中的第一个,就占用锁,否者就会加入到等待队列中,以后安装FIFO的规则从队列中取到自己
非公平锁: 非公平锁比较粗鲁,上来就直接尝试占有锁,如果尝试失败,就再采用类似公平锁那种方式。
可重入锁和不可重入锁
可重入锁
可重入锁就是递归锁
指的是同一线程外层函数获得锁之后,内层递归函数仍然能获取到该锁的代码,在同一线程在外层方法获取锁的时候,在进入内层方法会自动获取锁
也就是说:线程可以进入任何一个它已经拥有的锁所同步的代码块
ReentrantLock / Synchronized 就是一个典型的可重入锁
作用:可重入锁的最大作用就是避免死锁。
不可重入锁
是指线程拿到一把锁之后,不能自由进入同一把锁所同步的其他代码
自旋锁
自旋锁:spinlock,是指尝试获取锁的线程不会立即阻塞,而是采用循环的方式去尝试获取锁,这样的好处是减少线程上下文切换的消耗,缺点是循环会消耗CPU
CAS,底层使用的就是自旋,自旋就是多次尝试,多次访问,不会阻塞的状态就是自旋
优缺点
优点:循环比较获取直到成功为止,没有类似于wait的阻塞
缺点:当不断自旋的线程越来越多的时候,会因为执行while循环不断的消耗CPU资源
悲/乐观锁
悲观锁
假定肯定会发生并发冲突,同步所有对数据相关的操作,读数据也上锁
乐观锁
假定不会发生并发冲突,在更新数据时若发现数据和之前获取的数据不一致,则读取最新的数据,并尝试更新
独占锁和共享锁
独占锁(写锁)
指该锁一次只能被一个线程所持有。对ReentrantLock和Synchronized而言都是独占锁
给资源加上写锁,线程可以修改资源,其他线程不能加锁(单写)
共享锁(读锁)
指该锁可以被多个线程锁持有
对ReentrantReadWriteLock其读锁是共享,其写锁是独占
写的时候只能一个人写,但是读的时候,可以多个人同时读
给资源加上读锁后只能读不能改,其他线程也只能加读锁,不能加写锁(多读)
为什么会有写锁和读锁
原来我们使用ReentrantLock创建锁的时候,是独占锁,也就是说一次只能一个线程访问,但是有一个读写分离场景,读的时候想同时进行,因此原来独占锁的并发性就没这么好了,因为读锁并不会造成数据不一致的问题,因此可以多个人共享读。多个线程 同时读一个资源类没有任何问题,所以为了满足并发量,读取共享资源应该可以同时进行,但是如果一个线程想去写共享资源,就不应该再有其它线程可以对该资源进行读或写。
读-读:能共存
读-写:不能共存
写-写:不能共存