Python 官方文档:入门教程 => 点击学习
目录一、相似之处:Lock锁 vs Synchronized 代码块二、Lock接口中的方法三、不同点:Lock锁 vs Synchronized 代码块四、锁的可重入性4.1. s
Lock锁是一种类似于synchronized 同步代码块的线程同步机制。从Java 5开始java.util.concurrent.locks
引入了若干个Lock锁的实现类,所以通常情况下我们不需要实现自己的锁,重要的是需要知道如何使用它们,了解它们实现背后的原理。
Lock锁api的基本使用方法和Synchronized 关键字大同小异,代码如下
Lock lock = new ReentrantLock(); //实例化锁
//lock.lock(); //上锁
boolean locked = lock.tryLock(); //尝试上锁
if(locked){
try {
//被锁定的同步代码块,同时只能被一个线程执行
}finally {
lock.unlock(); //放在finally代码块中,保证锁一定会被释放
}
}
synchronized(obj){
//被锁定的同步代码块,同时只能被一个线程执行
}
Lock锁使用看上去麻烦一点,但是java默认提供了很多Lock锁,能满足更多的应用场景。比如:基于信号量加锁、读写锁等等,关注我的专栏《java并发编程》,后续都会介绍。
Lock接口实现方法通常会维护一个计数器,当计数器=0的时候资源被释放,当计数器大于1的时候资源被锁定。
public interface Lock {
void lock();
void lockInterruptibly() throws InterruptedException;
boolean tryLock();
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
void unlock();
Condition newCondition();
}
使用synchronized同步块和使用Lock API 之间还是有一些区别的
”可重入“意味着某个线程可以安全地多次获得同一个锁对象,而不会造成死锁。
下面的代码synchronized代码块嵌套synchronized代码块,锁定同一个this对象,不会产生死锁。证明synchronized代码块针对同一个对象加锁,是可重入的。
public void testLock(){
synchronized (this) {
System.out.println("第1次获取锁,锁对象是:" + this);
int index = 1;
do {
synchronized (this) {
System.out.println("第" + (++index) + "次获取锁,锁对象是:" + this);
}
} while (index != 10);
}
}
上面的这段代码输出结果是
第1次获取锁,锁对象是:com.example.demo.thread.TestLockReentrant@769c9116
第2次获取锁,锁对象是:com.example.demo.thread.TestLockReentrant@769c9116
第3次获取锁,锁对象是:com.example.demo.thread.TestLockReentrant@769c9116
第4次获取锁,锁对象是:com.example.demo.thread.TestLockReentrant@769c9116
第5次获取锁,锁对象是:com.example.demo.thread.TestLockReentrant@769c9116
第6次获取锁,锁对象是:com.example.demo.thread.TestLockReentrant@769c9116
第7次获取锁,锁对象是:com.example.demo.thread.TestLockReentrant@769c9116
第8次获取锁,锁对象是:com.example.demo.thread.TestLockReentrant@769c9116
第9次获取锁,锁对象是:com.example.demo.thread.TestLockReentrant@769c9116
第10次获取锁,锁对象是:com.example.demo.thread.TestLockReentrant@769c9116
Lock接口的实现类ReentrantLock,也是可重入锁。一般来说类名包含Reentrant的Lock接口实现类实现的锁都是可重入的。
public void testLock1(){
Lock lock = new ReentrantLock(); //实例化锁
lock.lock(); //上锁
System.out.println("第1次获取锁,锁对象是:" + lock);
try {
int index = 1;
do {
lock.lock(); //上锁
try {
System.out.println("第" + (++index) + "次获取锁,锁对象是:" + lock);
}finally {
lock.unlock();
}
} while (index != 10);
}finally {
lock.unlock(); //放在finally代码块中,保证锁一定会被释放
}
}
当线程第一次获得锁的时候,计数器被设置为1。在解锁之前,该线程可以再次获得锁,每次计数器都会增加1。对于每一个解锁操作,计数器被递减1,当计数器为0时锁定资源被释放。所以最重要的是:lock(tryLock)要与unlock方法成对出现,即:在代码中加锁一次就必须解锁一次,否则就死锁
Java的synchronized 同步块对试图进入它们的线程,被授予访问权(占有权)的优先级顺序没有任何保证。因此如果许多线程不断争夺对同一个synchronized 同步块的访问权,就有可能有一个或多个线程从未被授予访问权。这就造成了所谓的 "线程饥饿"。为了避免这种情况,锁应该是公平的。
Lock lock = new ReentrantLock(true);
可重入锁提供了一个公平性参数fairness ,通过该参数Lock锁将遵守锁请求的顺序,即在一个线程解锁资源后,锁将被交给等待时间最长的线程。这种公平模式是通过在锁的构造函数中传递 "true "来设置的。
以上就是java并发编程Lock锁可重入性与公平性分析的详细内容,更多关于并发Lock锁可重入性公平性的资料请关注编程网其它相关文章!
--结束END--
本文标题: java并发编程Lock锁可重入性与公平性分析
本文链接: https://lsjlt.com/news/148692.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
2024-03-01
2024-03-01
2024-03-01
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0