公平和非公平锁
公平锁:
多个线程按照申请的顺序来取锁,先来后到。
非公平锁:
不是按照来的顺序,上来就尝试占有锁,尝试失败再变成公平锁的方式申请锁,可能后申请的线程先获取锁,造成优先级反转和饥饿。
ReentrantLock默认非公平锁,可以通过传入boolean来改变。Synchronized也是非公平。
可重入锁(递归锁)
线程可以进入任何一个它已经拥有锁的同步代码块。一个线程获取到外层方法的锁,再进入该内层方法会自动获取锁,前提是二者锁同一对象。
ReentrantLock和synchronized非公平的可重入锁。
防止死锁。
synchronized(obj){
synchronized(obj){
//如果外层可以进,那么内层也可以进
}
}
自旋锁
尝试获取锁时不会阻塞,而是采用循环的方式尝试获取锁,减少线程上下文的切换的消耗,缺点循环会消耗CPU。
//unsafe.getAndAddInt
//var2内存偏移
public final int getAndAddInt( Object var1, long var2 , int var4){
int var5;
do {
var5 = this.getIntVolatile(var1,var2);
//如果之前获取的var5在主内存中没被修改,则将新增写入,如果已经修改,则再次读取var5,直到成功写入内存
}while( !this.compareAndSwapInt( var1, var2, var5, var5+var4));
return var5;
}
自旋锁CAS详细介绍
https://blog.csdn.net/D1124615130/article/details/116159936?spm=1001.2014.3001.5501
读写锁
读-读共存
写-写互斥
写-读互斥
写操作:原子+独占 整个过程是一个完整体,中间不得分割
classMyCache{
private volatile Map<String,Object> map = new HashMap<>();
private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
public void put(String key,Object value){
readWriteLock.writeLock().lock();
try{
System.out.println(Thread.currentThread().getName()+"写入"+key);
try{Thread.sleep(300);}catch(InterruptedExceptione){e.printStackTrace();}
map.put(key,value);
System.out.println(Thread.currentThread().getName()+"写入完成");
}catch(Exceptione){
e.printStackTrace();
}finally{
readWriteLock.writeLock().unlock();
}
}
public void get(String key){
readWriteLock.readLock().lock();
try{
System.out.println(Thread.currentThread().getName()+"读");
try{Thread.sleep(300);}catch(InterruptedExceptione){e.printStackTrace();}
Objecto = map.get(key);
System.out.println(Thread.currentThread().getName()+"读取完成"+o);
}catch(Exceptione){
e.printStackTrace();
}finally{
readWriteLock.readLock().unlock();
}
}
}
/**
*读可以共存
*读写不能共存
*写写不能共存
*/
public class ReadWriteLockDemo{
public static void main(String[] args){
MyCache myCache = new MyCache();
for(int I = 0 ; I < 5 ; i++){
final int tmp = I ;
new Thread( () -> {
myCache.put(tmp+"",tmp+"");
},String.valueOf(i)).start();
}
for(int i = 0 ; i < 5 ; i++){
final int tmp = i;
new Thread( () -> {
myCache.get(tmp+"");
},String.valueOf(i)).start();
}
}
}
运行结果
0写入0
0写入完成
1写入1
1写入完成
2写入2
2写入完成
3写入3
3写入完成
4写入4
4写入完成
0读
1读
2读
3读
4读
0读取完成0
3读取完成3
4读取完成4
1读取完成1
2读取完成2