java并发编程实践 2.3 锁

缘起

《java并发编程实践》 2.3小节

分析

【1】中已经提及了java内部提供的锁机制——即所谓的synchronized关键字. 并且指出了——为了维护多个状态的一致性(或者数据完整性),要在单一的原子操作中更新互相关联的状态变量.

synchronized关键字锁定的是一个对象(成员方法)或者Class字节码对象(静态方法).其实任何一个非null的java对象都可以都可以扮演一个锁. synchronized关键字又叫做内部锁或者互斥锁.

线程获取它的唯一途径是进入执行的代码块. 线程结束持有它的唯一途径就是结束代码块或者抛出异常. 持有期间,其他线程只能望锁兴叹.

被synchronized关键字保护的代码就和事务一样——原子性的一组语句,不可分割.

有的时候synchronized关键字如果锁住一大片的话,虽然能保持线程安全,但是大大降低了程序的响应性能.

最后谈及的问题是所谓的可重入性. synchronized锁是可重入的——即线程试图获取自己当前占有的锁的时候是会成功的. 这意味着synchronized关键字是每线程(per thread)而不是每调用(per call,per call 是POSIX的标准). 可重入的实现是,每个锁会关联一个重入次数计数器+线程, 如果来的是已经关联的线程的话,允许再次获取,并且将计数器+1,否则的话不允许进入. 线程退出的时候,计数器-1,直至减到零为止. 为0了,表示当前锁没有线程占用——锁被释放了.

锁的可重入性是必要的,不然很容易发生死锁

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Parent {
public synchronized void doSth() {
...
}
}

public class Child {
@Override
public synchronized void doSth() {
...
super.doSth();
}
}

如果不允许synchronized锁的重入性的话,则调用子类的doSth方法的时候,2次需要获取子类对象的锁. 则会死锁的.

参考

【1】https://yfsyfs.github.io/2019/06/22/java%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B%E5%AE%9E%E8%B7%B5-2-2-%E5%8E%9F%E5%AD%90%E6%80%A7/