💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
[TOC] > ### `Lock` * `synchronized`的缺陷,等待时间过长,需要有一种机制可以不让等待的线程一直无期限地等待下去(比如只等待一定的时间或者能够响应中断),通过`Lock`就可以办到。 * `Lock`不是Java语言内置的,`synchronized`是Java语言的关键字,因此是内置特性。`Lock`和`synchronized`有一点非常大的不同,采用`synchronized`不需要用户去手动释放锁,当`synchronized`方法或者`synchronized`代码块执行完之后,系统会自动让线程释放对锁的占用;而`Lock`则必须要用户去手动释放锁,如果没有主动释放锁,就有可能导致出现死锁现象。 * `Lock`是一个接口,`ReentrantLock`是唯一实现了`Lock`接口的类。 * 不要将获取锁的过程写在`try`块中,因为如果在获取锁(自定义锁的实现)时发生了异常,异常抛出的同时,也会导致锁无故释放。 <br/> > ### `Lock`与`synchronized`比较 ![](https://i.loli.net/2019/03/11/5c85d58d81a5a.png) <br/> > ### `Lock`接口的相关`api` ![](https://i.loli.net/2019/03/11/5c85d52e252f0.png) ``` public class Test { private ArrayList<Integer> arrayList = new ArrayList<Integer>(); private Lock lock = new ReentrantLock(); //注意这个地方 public static void main(String[] args) { final Test test = new Test(); new Thread(){ public void run() { test.insert(Thread.currentThread()); }; }.start(); new Thread(){ public void run() { test.insert(Thread.currentThread()); }; }.start(); } public void insert(Thread thread) { //加锁 lock.lock(); try { System.out.println(thread.getName()+"得到了锁"); for(int i=0;i<5;i++) { arrayList.add(i); } } catch (Exception e) { // TODO: handle exception }finally { System.out.println(thread.getName()+"释放了锁"); //释放锁 lock.unlock(); } } } ``` <br/> > ### `ReentrantLock` <br/> > ### `Condition` * `Condition`定义了等待/通知两种类型的方法,当前线程调用这些方法时,需要提前获取到`Condition`对象关联的锁。`Condition`对象是由`Lock`对象(调用`Lock`对象的`newCondition()`方法)创建出来的,换句话说,`Condition`是依赖`Lock`对象的。 * 一般都会将`Condition`对象作为成员变量。当调用`await()`方法后,当前线程会释放锁并在此等待,而其他线程调用`Condition`对象的`signal()`方法,通知当前线程后,当前线程才从`await()`方法返回,并且在返回前已经获取了锁。 > ### 三个线程 循环打印 ABC `lock condition` ``` public class LockConditionABC_3 { // lock condition 三个线程 循环打印 ABC // 参考 https://www.bbsmax.com/A/amd0ENEWzg/ public static void main(String[] args) throws InterruptedException { ReentrantLock lock = new ReentrantLock(); Condition conditionA = lock.newCondition(); Condition conditionB = lock.newCondition(); Condition conditionC = lock.newCondition(); Thread t1 = new Thread(new ThreadDemo(lock, conditionA, conditionB, 'A'), "ThreadA"); Thread t2 = new Thread(new ThreadDemo(lock, conditionB, conditionC, 'B'), "ThreadB"); Thread t3 = new Thread(new ThreadDemo(lock, conditionC, conditionA, 'C'), "ThreadC"); t1.start(); Thread.sleep(100); t2.start(); Thread.sleep(100); t3.start(); } static class ThreadDemo implements Runnable{ private final ReentrantLock reentrantLock; private final Condition thisCondtion; private final Condition nextCondtion; Character c; public ThreadDemo(ReentrantLock reentrantLock, Condition thisCondtion, Condition nextCondition, char c) { this.reentrantLock = reentrantLock; this.nextCondtion = nextCondition; this.thisCondtion = thisCondtion; this.c = c; } public void run(){ reentrantLock.lock(); try { // 连续打印 for (int i = 0; i < 5; i++) { System.out.println(Thread.currentThread().getName() + ":" + c); // 使用nextCondition唤醒下一个线程 // 因为只有一个线程在等待,所以signal或者signalAll都可以 nextCondtion.signal(); // 不是最后一次则通过thisCondtion等待被唤醒 // 必须要加判断,不然能够打印6次 但6次后就会直接死锁 if (i < 5 - 1) { try { // 本线程让出锁并等待唤醒 thisCondtion.await(); } catch (InterruptedException e) { e.printStackTrace(); } } } } finally { // 释放锁 reentrantLock.unlock(); } } } } ``` <br/> > ### `ReadWriteLock` * `ReadWriteLock`也是一个接口,`ReentrantReadWriteLock`是其的实现类,主要有两个方法:`readLock()`和`writeLock()`用来获取读锁和写锁。 * 读是共享读锁,写是独占锁阻塞其它的读写操作 ``` public class ReentrantReadWriteLockDemo { private static final Map<String, Object> map = new HashMap<String, Object>(); private static final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); private static final Lock readLock = lock.readLock(); private static final Lock writeLock = lock.writeLock(); public ReentrantReadWriteLockDemo() { if(map.size() == 0 ) map.put("0", "asd"); } //读写锁 //在同一时刻允许多个线程进行读操作 //但是有线程进行写操作时,阻塞其它线程的读写 public final Object get(String key, int threadId) { readLock.lock(); try { System.out.println("Thread: " + threadId + " > read " + key + "|" + map.get(key)); return map.get(key); } finally { readLock.unlock(); } } public final Object put(String key, Object value, int threadId) { writeLock.lock(); try { System.out.println("Thread: " + threadId + " > write " + key + " | " + value); SleepUtils.second(1000); return map.put(key, value); } finally { writeLock.unlock(); } } public final void clear() { writeLock.lock(); try { map.clear(); } finally { writeLock.unlock(); } } public static void main(String[] args) { ReentrantReadWriteLockDemo demo = new ReentrantReadWriteLockDemo(); for(int i = 0; i < 30; i++){ Thread thread = new Thread(new ThreadDemo(demo), String.valueOf(i)); thread.start(); } } public static class ThreadDemo implements Runnable{ ReentrantReadWriteLockDemo demo ; public ThreadDemo(ReentrantReadWriteLockDemo demo){ this.demo = demo; } public void run() { int i = Integer.valueOf(Thread.currentThread().getName()); if(i % 10 == 0){ demo.put(String.valueOf(i), Thread.currentThread().getName(), i); }else{ demo.get(String.valueOf(0), i); } } } static class SleepUtils{ public static void second(int i){ try { Thread.sleep(i); } catch (InterruptedException e) { e.printStackTrace(); } } } } ``` <br/> <br/> *** 参考: [ReentrantLock(重入锁)以及公平性](http://ifeve.com/reentrantlock-and-fairness/)