03 有关锁的其他概念.txt
UP 返回
1 公平锁 (参视频24)
公平是针对锁的获取而言的,如果一个锁是公平的,那么锁的获取顺序就应该符合请求的绝对时间顺序
2 读写锁 (参视频25)
2.1 排他锁与共享锁
当同时只有一个线程可以访问的锁为排它锁。自旋的锁也是
同一时刻可以允许多个线程同时访问则为共享锁,比如读线程
读锁之间互斥;读与写操作互斥;读锁之间不互斥。测试代码如下:
public class Demo {
private Map<String, Object> map = new HashMap<>();
private ReadWriteLock rwl = new ReentrantReadWriteLock();// ★读写锁
private Lock r = rwl.readLock();// ★获取读锁
private Lock w = rwl.writeLock();// ★获取写锁
public Object get(String key) {
r.lock();
System.out.println(Thread.currentThread().getName() + " 读操作执行中");
try {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return map.get(key);
} finally {
r.unlock();
System.out.println(Thread.currentThread().getName() + " 读操作完毕");
}
}
public void put(String key, String value) {
w.lock();
System.out.println(Thread.currentThread().getName() + " 写操作执行中");
try {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
map.put(key, value);
} finally {
w.unlock();
System.out.println(Thread.currentThread().getName() + " 写操作完毕");
}
}
}
3 锁降级
锁降级是指写锁降级为读锁。在写锁没有释放的时候,获取到读锁,再释放写锁
在上述Demo类中添加变量private volatile boolean isUpdate;用于判断是否是读写操作
public void readWrite() { //测试读写操作
r.lock();
if (isUpdate) {
r.unlock();
w.lock();
map.put("xxx", "xxx");
r.lock(); //写入以后如果直接释放写锁,会使其他线程马上竞争获取写锁,可能会重新写入新的值导致读写数据不一致。故释放写锁之前先获取读锁,防止写线程获取,此即为锁降级
w.unlock();
}
Object object = map.get("xxx");
System.out.println(object);
r.unlock();
}
锁升级
与之相对的,把读锁升级为写锁即为锁升级。是指在读锁没有释放的时候,获取到写锁,再释放读锁。
读写锁中读锁未释放时,是不可能拿到写锁的,所以读写锁中不存在锁升级!
4 重排序 参视频58
什么是重排序
编译器和处理器为了提高程序的运行性能,对指令进行重新排序。
数据依赖性(as-if-serial)
当存在读后写 写后读 写后写时,不会有指令重排序;当两条语句数据之间不存在相互依赖,即会可能发生重排序
指令重排序分类
编译器重排序和处理器重排序
为什么要进行指令重排序
指令重排序所带来的影响
竞争与同步
5 happens-before 参视频59
Happens-before是用来指定两个操作之间的执行顺序。提供跨线程的内存可见性。
在Java内存模型中,如果一个操作执行的结果需要对另一个操作可见,那么这两个操作之间必然存在happens-before关系。
Happens-before规则如下
程序顺序规则
监视器锁规则
volatile变量规则
传递性
Start规则
Join规则
5.1 程序顺序规则
单个线程中的每个操作,总是前一个操作happens-before于该线程中的任意后续操作
5.2 监视器规则
对一个锁的解锁,总是happens-before于随后对这个锁的加锁
5.3 volatile变量规则
对一个volatile域的写,happens-before于任意后续对这个volatile域的读
5.4 传递性
A happens-before B
B happens-before C
则
A happens-before C
5.5 Start规则
a线程中调用b,则a中的操作happens-before b
5.6 Join规则
6 锁的内存语义 参视频60
锁的释放与获取所建立的happens-before关系
锁的释放和获取的内存语义
锁除了让临界区互斥执行外,还可以让释放锁的线程向获取同一个锁的线程发送消息。
7 volatile的内存语义 参视频61
Volatile读写所建立的happens-before关系
Volatile读写的内存语义
锁对应: 获取和释放
Volatile对应: 读 和 写
当写一个volatile变量时,java内存模型会把该线程对应的本地内存中的共享变量值刷新到主内存中;当读一个volatile变量时,java内存模型会把当前线程对应的本地内存中的共享变量置为无效,从主内存中重新读取
8 final的内存语义 参视频62
8.1 写final域的重排序规则
写final域的重排序的规则禁止把final域的写 重排序到构造方法之外。
Java的内存模型禁止编译器把final域的写重排序到构造方法之外
编译器会在final域的写之后,在构造方法执行完毕之前,插入一个内存屏障StoreStore,保证处理器把final域的写操作在构造方法中执行。
LoadLoad load1 loadload load2
StoreStore store1 storestore store2
LoadStore
StoreLoad
8.2 读final域的重排序规则
在一个线程中,初次读对象引用和初次读该对象所包含的final域,Java内存模型禁止处理器重排序这两个操作。
8.3 Final域为抽象类型
在构造方法内对一个final引用的对象的成员域的写入,与随后在构造方法外把这个被构造对象的引用赋值给一个引用变量,这两个操作之间不能重排序。
DOWN 返回