在上面这段代码中,我们对 doSomething() 和 doSomethingElse() 分别使用了 synchronized 进行锁定,doSomething() 方法中调用了 doSomethingElse() 方法,因为 synchronized 是可重入锁,所以同一个线程在调用 doSomething() 方法时,也能够进入 doSomethingElse() 方法中。
不可重入锁如果 synchronized 是不可重入锁的话,那么在调用 doSomethingElse() 方法的时候,必须把 doSomething() 的锁丢掉,实际上该对象锁已被当前线程所持有,且无法释放。所以此时会出现死锁。
也就是说,不可重入锁会造成死锁
多个线程能够共享同一把锁 独占锁和共享锁独占多和共享锁一般对应 JDK 源码的 ReentrantLock 和 ReentrantReadWriteLock 源码来介绍独占锁和共享锁。
独占锁又叫做排他锁,是指锁在同一时刻只能被一个线程拥有,其他线程想要访问资源,就会被阻塞。JDK 中 synchronized和 JUC 中 Lock 的实现类就是互斥锁。
共享锁指的是锁能够被多个线程所拥有,如果某个线程对资源加上共享锁后,则其他线程只能对资源再加共享锁,不能加排它锁。获得共享锁的线程只能读数据,不能修改数据。
我们看到 ReentrantReadWriteLock 有两把锁:ReadLock 和 WriteLock,也就是一个读锁一个写锁,合在一起叫做读写锁。再进一步观察可以发现 ReadLock 和 WriteLock 是靠内部类 Sync 实现的锁。Sync 是继承于 AQS 子类的,AQS 是并发的根本,这种结构在CountDownLatch、ReentrantLock、Semaphore里面也都存在。
在 ReentrantReadWriteLock 里面,读锁和写锁的锁主体都是 Sync,但读锁和写锁的加锁方式不一样。读锁是共享锁,写锁是独享锁。读锁的共享锁可保证并发读非常高效,而读写、写读、写写的过程互斥,因为读锁和写锁是分离的。所以ReentrantReadWriteLock的并发性相比一般的互斥锁有了很大提升。
欢迎关注
文章参考:
https://baike.baidu.com/item/悲观锁
https://blog.csdn.net/qq_34337272/article/details/81252853
https://blog.hufeifei.cn/ 关于自旋锁的文章
https://en.wikipedia.org/wiki/Ticket_lock
https://blog.stephencleary.com/2013/04/recursive-re-entrant-locks.html
https://researcher.watson.ibm.com/researcher/files/us-bacon/Bacon03Retrospective.pdf
https://tech.meituan.com/2018/11/15/java-lock.html
https://www.jianshu.com/p/eaea337c5e5b
https://blog.csdn.net/oChangWen/article/details/77622889