赞
踩
锁策略可以理解为,这把锁在加锁/解锁/遇到锁冲突的时候都会怎么做
并非局限于Java中,其他编程语言,其他的系统级别的组件,但凡涉及到锁,都和锁策略有关系
加锁的时候,预测当前锁冲突的概率是大还是小
Java中的synchronized既是乐观锁也是悲观锁,支持自适应,能够自动的统计出当前锁冲突的次数,进行判定当前锁冲突的概率高低
悲观锁往往是要通过内核来完成一些操作的,要做的工作就多
乐观锁往往是纯用户态的一些操作,要做的工作就少
一般来说,悲观锁往往就是重量级锁;乐观锁往往就是轻量级锁
//伪代码
void lock() {
while(true) {
if(锁是否被占用) {
continue;
}
获取到锁
break;
}
}
cpu在空转,忙等,消耗了更多的CPU资源,但是一旦锁被释放,就能第一时间拿到锁
挂起等待锁是重量级锁的一种典型实现方式
synchronized轻量级锁部分,基于自旋锁实现;重量级锁部分,基于挂起等待锁实现
Java中的synchronized是可重入锁,一个线程针对同一把锁连续加锁两次,不会死锁
C++中的std::mutex是不可重入锁,一个线程针对同一把锁连续加锁两次,会出现死锁
synchronized属于非公平锁,多个线程尝试获取到这个锁,此时是按照概率均等的方式进行获取
系统本身线程调度的顺序就是随机的,如果需要实现公平锁,就需要引入额外的队列,按照加锁顺序,把这些获取锁的线程入队列,再一个一个出队列
互斥锁:一个线程获取到锁并进行加锁,另一个线程就不能对其加锁了
读写锁:多个线程读同一个变量,不会有线程安全问题
突出体现的是读操作和读操作之间是共享的,不会互斥的,有利于降低锁冲突的概率,提高并发能力
日常开发中,有很多场景,属于**”读多,写少“**,大部分操作都是读,偶尔有写的操作
如果使用普通的互斥锁,此时,每次读操作之间都会互斥,影响效率
如果使用读写锁,就能够有效的降低锁冲突的概率,提高效率
Java标准库/操作系统api也提供了读写锁的实现
synchronized既是悲观锁,也是乐观锁,既是轻量级锁,也是重量级锁,轻量级锁是自旋锁实现,重量级锁是挂起等待锁实现,是可重入锁,不是读写锁,是非公平锁
那么synchronized如何”自适应“
锁升级的过程:
偏向锁
上述的升级过程,针对一个锁对象来说,是不可逆的,只能升级不能降级,一旦升级到重量级锁,不会回退到轻量级锁
锁消除是一种编译器优化策略
代码中写了加锁操作,编译器和JVM会对当前的代码做出判定,看这个地方是否真的需要加锁,如果不需要加锁,就会自动把加锁操作给优化掉
最典型的就是:在只有一个线程里,使用synchronized
由于编译器优化,需要保证优化后的逻辑和优化前要等价,这里做的是比较保守的,能够起到的作用有限,与之前谈到的偏向锁互不相干,也不冲突
锁的粒度:加锁的范围内,包含多少代码,代码越多,就认为锁的粒度越粗,反之越细
锁粗化:一种优化策略,有些逻辑中,需要频繁加锁解锁,编译器就会自动的把多次细粒度的锁,合并成一次粗粒度的锁
例如:领导安排了三个工作
CAS:compare and swap(比较和交换),这是一条CPU指令,就可以完成比较和交换这一套操作
可以将CAS的流程想象成一个方法
boolean cas(address, reg1, reg2){
if(*address == reg1){
把address内存地址的值和reg2寄存器的值进行交换
return true;
}
return false;
}
这里说的交换,实际更多的是用来赋值,一般更关心内存中交换后的数据,而不关心reg2寄存器交换后的数据,可以近似认为上述操作把reg2的值赋值给内存中
由于CPU提供了上述指令,因此操作系统内核,也就能够完成上述操作,就会提供出这样的CAS的api,JVM又对于系统的CAS的api进一步封装了,在Java代码中就可以使用CAS操作了
但是实际上,CAS被封装到了一个unsafe包中,容易出错,不鼓励大家直接使用CAS
Java中也有一些类,对CAS进行了进一步的封装,典型的就是原子类
例如java.util.comcurrent.atomia
中的AtomicInteger
,相当于针对int进行了封装,可以保证此处的++或–操作,是原子的
Java中不支持运算符重载,无法针对原子类进行++、–;C++和python能够支持运算符重载,可以重新定义±*/等各种运算符的作用
package thread; import java.util.concurrent.atomic.AtomicInteger; public class Demo38 { private static AtomicInteger count = new AtomicInteger(0); public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(()->{ //count++ count.getAndIncrement(); //++count count.incrementAndGet(); //count-- count.getAndDecrement(); //--count count.decrementAndGet(); //count+=10 count.getAndAdd(10); }); t1.start(); t1.join(); System.out.println("count = " + count); } }
此处我们的代码中,没有用到任何加锁操作,使得代码以更高的效率来执行程序
这一套基于CAS不加锁来实现线程安全代码的方式,也成为无锁编程
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。