Java并发编程Lock锁可重入性与公平性分析
1. Lock锁的可重入性
1.1 可重入性的概念
Lock锁是一种可重入锁,也就是说当一个线程获取到了Lock锁之后,在没有释放锁的情况下,该线程可以再次获取到该锁而不会发生死锁现象。因此,Lock锁的可重入性是很重要的一个特点,也是区别于synchronized同步块的一个重要特点。
1.2 Lock锁的重入
以下代码展示了Lock锁的重入:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LockReentrantDemo {
Lock lock = new ReentrantLock();
public void outer(){
lock.lock(); // 获取锁
inner();
lock.unlock(); // 释放锁
}
public void inner(){
lock.lock(); // 获取锁
// 执行相应的操作
lock.unlock(); // 释放锁
}
}
在 outer 方法中获取了锁之后,进入到 inner 方法中,同时也获取到了锁,此时如果不释放锁,那么 outer 和 inner 都会被一直阻塞住,这就是死锁现象。因此,为了避免死锁,Lock锁必须是可重入的。
2. Lock锁的公平性
2.1 公平性的概念
Lock锁有公平锁和非公平锁两种Lock的实现方式。公平锁的含义是多个线程在等待Lock锁时将按照申请时间的先后顺序依次进行获取锁。而非公平锁则是多个线程在等待Lock锁时,哪个线程先获取到锁就由哪个线程进入临界区。
2.2 公平锁实现分析
公平锁是通过内部维护一个FIFO队列来实现的,FIFO就是先进先出的意思。
以下代码演示了如何创建公平锁:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class FairLockDemo {
Lock lock = new ReentrantLock(true); // 创建公平锁
public void executeTask(){
lock.lock(); // 获取锁
try {
// 执行相应的任务
} finally {
lock.unlock(); // 释放锁
}
}
}
在创建ReentrantLock实例时,需要传入一个Boolean类型的参数,该参数为true时,锁为公平锁,为flase时,锁为非公平锁。在上述代码中创建Lock实例时,传入了true,即表明创建了一个公平锁。
2.3 非公平锁实现分析
以下代码演示了如何创建非公平锁:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class UnfairLockDemo {
Lock lock = new ReentrantLock(false); // 创建非公平锁
public void executeTask(){
lock.lock(); // 获取锁
try {
// 执行相应的任务
} finally {
lock.unlock(); // 释放锁
}
}
}
在上述代码中创建Lock实例时,传入了false,即表明创建了一个非公平锁。
3. 示例说明
3.1 示例1
以下示例是一个公平锁的使用:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class FairLockDemo {
Lock lock = new ReentrantLock(true); // 创建公平锁
public void executeTask(){
lock.lock(); // 获取锁
try {
// 执行相应的任务
} finally {
lock.unlock(); // 释放锁
}
}
}
public class FairLockDemoTest {
public static void main(String[] args) {
FairLockDemo fairLockDemo = new FairLockDemo(); // 创建公平锁示例
// 创建线程A和B
Thread threadA = new Thread(new Runnable() {
@Override
public void run() {
fairLockDemo.executeTask();
}
}, "A");
Thread threadB = new Thread(new Runnable() {
@Override
public void run() {
fairLockDemo.executeTask();
}
}, "B");
threadA.start(); // 启动线程A
threadB.start(); // 启动线程B
}
}
在上述示例中,创建一个公平锁FairLockDemo实例,创建线程A和B分别去执行任务时,A线程先获取到锁,B线程就会被阻塞,直到A线程释放锁后,B线程才可以去获取锁。
3.2 示例2
以下示例是一个非公平锁的使用:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class UnfairLockDemo {
Lock lock = new ReentrantLock(false); // 创建非公平锁
public void executeTask(){
lock.lock(); // 获取锁
try {
// 执行相应的任务
} finally {
lock.unlock(); // 释放锁
}
}
}
public class UnfairLockDemoTest {
public static void main(String[] args) {
UnfairLockDemo unfairLockDemo = new UnfairLockDemo(); // 创建非公平锁Demo
// 创建线程A和B
Thread threadA = new Thread(new Runnable() {
@Override
public void run() {
unfairLockDemo.executeTask();
}
}, "A");
Thread threadB = new Thread(new Runnable() {
@Override
public void run() {
unfairLockDemo.executeTask();
}
}, "B");
threadA.start(); // 启动线程A
threadB.start(); // 启动线程B
}
}
在上述示例中,创建一个非公平锁UnfairLockDemo实例,创建线程A和B去执行任务时,A线程和B线程同时去获取锁,由于锁为非公平锁,因此谁后执行完毕就会先获取锁。因此经过多次实验,结果不唯一。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:java并发编程Lock锁可重入性与公平性分析 - Python技术站