ReentrantLock
在多线程中可以使用,Synchronized关键字实现线程与线程之间的同步互斥 但在JDK1.5中新增ReentrantLock类也能达到相同的目的, 并且扩展的功能也十分强大 比如 嗅探锁定/多路分支通知等功能, 而且在使用上也比Synchronized灵活很多
ReentrantLock 实现同步
public class ReentrantLockTest {
static ReentrantLock reentrantLock = new ReentrantLock(); // 声明ReentrantLock
public static void main(String[] args) {
try {
reentrantLock.lock(); // 加锁
// ----
} catch (Exception e) {
e.printStackTrace();
} finally {
reentrantLock.unlock(); // 解锁
}
}
}
Condition 讲解
Synchronized 可以通过wait()/notify()/notifyAll() 实现 等待/通知模式, ReentrantLock 可以使用Condition类实现相同的功能, Condition 更加灵活, 比如实现多路通知功能 一个ReentrantLock对象可以创建多个Condition, 线程对象可以选择性的, 注册到不同的Condition上, 从而选择性的进行线程通知,
简单实现
condition.await() 方法必须在reentrantLock.lock() 方法内. 否则会提示异常信息
public class MyService {
private ReentrantLock reentrantLock = new ReentrantLock();
private Condition condition = reentrantLock.newCondition();
private List<String> arrayList = new ArrayList<>();
public void addItems() {
try {
reentrantLock.lock();
if (arrayList.size() <= 0) {
arrayList.add("新增一跳数据");
System.out.println("addItems -- > 开始等待删除");
condition.await();
}
System.out.println("addItems -- > 执行完了");
} catch (Exception e) {
} finally {
reentrantLock.unlock();
}
}
public void removeItems() {
try {
reentrantLock.lock();
if (arrayList.size() >= 0) {
arrayList.remove(0);
System.out.println("removeItems -- > 元素已删除");
condition.signal();
}
System.out.println("removeItems -- > 执行完了");
} catch (Exception e) {
} finally {
reentrantLock.unlock();
}
}
}
public class Run {
public static void main(String[] args) throws InterruptedException {
MyService myService = new MyService();
new Thread(() -> {
myService.addItems();
}).start();
Thread.sleep(1000);
new Thread(() -> {
myService.removeItems();
}).start();
}
}
唤醒指定线程
public class MyService {
private ReentrantLock reentrantLock = new ReentrantLock();
private Condition condition = reentrantLock.newCondition();
private Condition conditionA = reentrantLock.newCondition();
public void awaitA() {
try {
reentrantLock.lock();
System.out.println("conditionA await 时间:" + System.currentTimeMillis());
conditionA.await();
System.out.println("conditionA 唤醒 时间:" + System.currentTimeMillis());
} catch (Exception e) {
} finally {
reentrantLock.unlock();
}
}
public void await() {
try {
reentrantLock.lock();
System.out.println("condition await 时间:" + System.currentTimeMillis());
condition.await();
System.out.println("condition 唤醒 时间:" + System.currentTimeMillis());
} catch (Exception e) {
} finally {
reentrantLock.unlock();
}
}
public void signalA() {
try {
reentrantLock.lock();
System.out.println("conditionA signal 时间:" + System.currentTimeMillis());
conditionA.signal();
System.out.println("conditionA signal 结束时间:" + System.currentTimeMillis());
} catch (Exception e) {
} finally {
reentrantLock.unlock();
}
}
}
public class Run {
public static void main(String[] args) throws InterruptedException {
MyService myService = new MyService();
new Thread(() -> {
myService.await();
}).start();
new Thread(() -> {
myService.awaitA();
}).start();
Thread.sleep(1000);
new Thread(() -> {
myService.signalA();
}).start();
}
}
公平锁与非公平锁
ReentrantLock 分为 公平锁/非公平锁 公平锁表示: 线程获取锁的顺序是根据加锁的顺序, FIFO先进先出的原则 非公平锁表示: 获取锁是抢占机制, 是随机获得锁, 这个方式可能影响某些线程一直拿不到锁
// 默认非公平锁
public ReentrantLock() {
sync = new NonfairSync();
}
// 传递 true = 公平锁, false = 非公平锁
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
公平锁
public class MyService {
private ReentrantLock reentrantLock = new ReentrantLock(true);
public void awaitA() {
try {
reentrantLock.lock();
System.out.println(Thread.currentThread().getName() + "_ 获得锁");
} catch (Exception e) {
} finally {
reentrantLock.unlock();
}
}
}
public class Run {
public static void main(String[] args) throws InterruptedException {
MyService myService = new MyService();
List<Thread> arr = new ArrayList<>();
for (int i = 0; i < 11; i++) {
Thread thread = new Thread(() -> {
System.out.println(Thread.currentThread().getName()+"_ 运行了");
myService.awaitA();
}, i + "");
arr.add(thread);
}
for (Thread thread : arr) {
thread.start();
}
}
}
0_ 运行了
4_ 运行了
2_ 运行了
3_ 运行了
1_ 运行了
0_ 获得锁
4_ 获得锁
2_ 获得锁
3_ 获得锁
1_ 获得锁
可以看出来 根据线程被CPU调度的顺序, 也就是线程获得锁的顺序
非公平锁
只修改 初始化 ReentrantLock的方式
public class MyService {
private ReentrantLock reentrantLock = new ReentrantLock(false);
public void awaitA() {
try {
reentrantLock.lock();
System.out.println(Thread.currentThread().getName() + "_ 获得锁");
} catch (Exception e) {
} finally {
reentrantLock.unlock();
}
}
}
0_ 运行了
3_ 运行了
2_ 运行了
4_ 运行了
1_ 运行了
0_ 获得锁
3_ 获得锁
2_ 获得锁
4_ 获得锁
1_ 获得锁
顺序被打乱了
关键方法
hasQueuedThread(Thread thread)
查询指定线程是否正在等待获取此锁
HasQueuedThreads()
查询是否有线程正在等待获取此锁
hasWaiters()
查询是否有等待Condition的线程
hasQueueLength()
查询等待Condition的线程数量
isFair()
判断是否是公平锁
isHeldByCurrentThread()
查询当前线程是否是锁定状态
isLocked()
查询次锁定是否由任意线程保持
lockInterruptibly()
如果当前线程未被中断则获得锁定, 如果已被中断, 抛出异常
tryLock()
如果未被其他线程保持的情况下, 获得锁
tryLock(long timeout, TimeUnit unit)
在指定时间内没有被其他锁保持, 或者其他锁释放了锁, 则获取锁
Condition#awaitUninterruptibly
如果单独使用await() 方法然后调用中断会提示错误, 如果使用awaitUninterruptibly 则会正常向下执行
|