1.简介
ReentrantLock锁实现了一种可重入锁(reentrat lock)
,当持有该锁的线程能够重复进入该锁
,例如重复调用lock方法
,计数器会自增必须通过调用相同次数的unlock
进行抵消,其他获取该锁的线程会被挂起
,如果抵消的次数不够就会一直挂起
一般都会在finally块中使用unlock
,用来确保一定会被解锁
2.api
构造函数:
方法:
3.例子
/**
* @description 用于测试ReentrantLock锁
* @author hy
* @date 2019-10-12
*/
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockTest {
public static void main(String[] args) {
ReentrantLockTest lockTest = new ReentrantLockTest();
lockTest.testReentrantLock();
}
ReentrantLock lock = new ReentrantLock();
public void testReentrantLock() {
new Thread(() -> {
run();
}, "A").start();
new Thread(() -> {
run();
}, "B").start();
new Thread(() -> {
run();
}, "C").start();
}
// 执行的方法
public void run() {
String name = Thread.currentThread().getName();
for (int i = 0; i < 3; i++) {
lock.lock();
System.out.println(name + "线程执行:锁定操作");
System.out.println(name + "线程执行:业务操作");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
lock.unlock();
System.out.println(name + "线程执行:解锁操作");
}
}
}
}
当前创建的锁为非公平锁的例子的结果:
发现当前的执行为抢夺cpu资源的竞争状态的锁!
修改为公平锁 ReentrantLock lock = new ReentrantLock(true);的执行结果:
发现执行多次都是一样的结果:当前线程按照一定的顺序执行,公平的享有执行的cpu!
4.使用Condition的例子
存钱和取钱的例子
/**
* @description 测试ReentrantLock的Condition
* @author hy
* @date 2019-10-13
*/
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockConditionTest {
private ReentrantLock lock = new ReentrantLock();
private Condition saveable = lock.newCondition();// 定义可以存钱的条件
private Condition outable = lock.newCondition();// 定义可以取钱的条件
private volatile int money = 0;
public int getMoney() {
try {
lock.lock();
return money;
} finally {
lock.unlock();
}
}
public void setMoney(int money) {
try {
lock.lock();
this.money = money;
} finally {
lock.unlock();
}
}
public static void main(String[] args) {
ReentrantLockConditionTest conditionTest = new ReentrantLockConditionTest();
conditionTest.start();
}
public void start() {
new Thread(new Saver()).start();
new Thread(new Outer()).start();
new Thread(new Saver()).start();
new Thread(new Outer()).start();
}
//取钱的人
class Saver implements Runnable {
@Override
public void run() {
while (true) {
doSaver();// 执行存钱的方法
}
}
// 存钱的方法
void doSaver() {
lock.lock();
if (getMoney() >= 1000) {//对于存钱的来说:当前金额大于等于1000的时候就让存钱的线程停止执行,唤醒取钱的线程
try {
saveable.await();
outable.signal();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else {//否者两者线程都唤醒
saveable.signal();
outable.signal();
}
lock.unlock();
// 执行存钱的方法
String name = Thread.currentThread().getName();
try {
money += 100;
System.out.println(name + "-线程执行存钱的操作:+100,当前money=" + money);
Thread.sleep(200);// 模拟线程延迟
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
//存钱的人的类
class Outer implements Runnable {
@Override
public void run() {
while (true) {
doOuter();// 执行存钱的方法
}
}
// 存钱的方法
void doOuter() {
lock.lock();
if (getMoney() <= 0) {//对于取钱的来说:当前金额小于等于0的时候就让取钱的线程停止执行,唤醒存钱的线程
try {
outable.await();
saveable.signal();
} catch (InterruptedException e) {
e.printStackTrace();
}
}else{//否者两者线程都唤醒
outable.signal();
saveable.signal();
}
lock.unlock();
// 执行存钱的方法
String name = Thread.currentThread().getName();
try {
money -= 100;
System.out.println(name + "-线程执行存钱的操作:-100,当前money=" + money);
Thread.sleep(200);// 模拟线程延迟
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
结果:
测试成功!
5.总结
1.在创建ReentrantLock的时候可以通过当前的构造函数设置是否为公平锁和非公平锁
2.通过lock进行锁定通过unlock
进行解锁(解锁通常用在finally块)
3.通过ReentrantLock的newCondition方式创建执行的条件
,其中使用awiat方法和signal(signalAll)的时候需要先开启锁
才能使用(类似于线程中的用法,没有锁的线程是不能执行的
)
4.公平锁
执行的时候按照一定的顺序执行
,非公平锁
是按照抢夺cpu资源来执行的
以上纯属个人简介,如有问题请联系本人!