💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
[TOC] # ReentrantLock ## lock用法 ReentrantLock,意思是“可重入锁”。ReentrantLock是唯一实现了Lock接口的类,并且ReentrantLock提供了更多的方法。下面通过一些实例看具体看一下如何使用ReentrantLock。 例子1,lock()的正确使用方法 ~~~ package testThread; import java.util.ArrayList; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class TestThread { private ArrayList<Integer> arrayList = new ArrayList<Integer>(); public static void main(String[] args) { final TestThread testThread = new TestThread(); new Thread() { public void run() { testThread.insert(Thread.currentThread()); } }.start(); new Thread() { public void run() { testThread.insert(Thread.currentThread()); } }.start(); } private void insert(Thread thread) { //注意这个地方 Lock lock = new ReentrantLock(); lock.lock(); try { System.out.println(thread.getName() + "得到了锁"); for (int i = 0; i < 5; i++) { arrayList.add(i); } } catch (Exception e) { e.printStackTrace(); } finally { System.out.println(thread.getName() + "释放锁"); lock.unlock(); } } } ~~~ 各位朋友先想一下这段代码的输出结果是什么? ~~~ Thread-0得到了锁 Thread-1得到了锁 Thread-1释放锁 Thread-0释放锁 ~~~ 也许有朋友会问,怎么会输出这个结果?第二个线程怎么会在第一个线程释放锁之前得到了锁?原因在于,在insert方法中的lock变量是局部变量,每个线程执行该方法时都会保存一个副本,那么理所当然每个线程执行到lock.lock()处获取的是不同的锁,所以就不会发生冲突。 知道了原因改起来就比较容易了,只需要将lock声明为类的属性即可 ~~~ package testThread; import java.util.ArrayList; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class TestThread { private ArrayList<Integer> arrayList = new ArrayList<Integer>(); private Lock lock = new ReentrantLock(); public static void main(String[] args) { final TestThread testThread = new TestThread(); new Thread() { public void run() { testThread.insert(Thread.currentThread()); } }.start(); new Thread() { public void run() { testThread.insert(Thread.currentThread()); } }.start(); } private 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) { e.printStackTrace(); } finally { System.out.println(thread.getName() + "释放锁"); lock.unlock(); } } } ~~~ 这样就是正确地使用Lock的方法了 ## tryLock ~~~ package testThread; import com.sun.org.apache.bcel.internal.generic.IF_ACMPEQ; import java.util.ArrayList; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class TestThread { private ArrayList<Integer> arrayList = new ArrayList<Integer>(); private Lock lock = new ReentrantLock(); public static void main(String[] args) { final TestThread testThread = new TestThread(); new Thread() { public void run() { testThread.insert(Thread.currentThread()); } }.start(); new Thread() { public void run() { testThread.insert(Thread.currentThread()); } }.start(); } private void insert(Thread thread) { if (lock.tryLock()) { try { System.out.println(thread.getName() + "得到了锁"); for (int i = 0; i < 5; i++) { arrayList.add(i); } } catch (Exception e) { e.printStackTrace(); } finally { System.out.println(thread.getName() + "释放锁"); lock.unlock(); } } else { System.out.println(thread.getName() + "获取锁失败"); } } } ~~~ 输出结果 ~~~ Thread-0得到了锁 Thread-0释放锁 Thread-1得到了锁 Thread-1释放锁 ~~~ ## lockInterruptibly lockInterruptibly()响应中断的使用方法: ~~~ public class Test { private Lock lock = new ReentrantLock(); public static void main(String[] args) { Test test = new Test(); MyThread thread1 = new MyThread(test); MyThread thread2 = new MyThread(test); thread1.start(); thread2.start(); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } //调用中断方法来测试能否中断等待中的线程 thread2.interrupt(); } public void insert(Thread thread) throws InterruptedException{ lock.lockInterruptibly(); //注意,如果需要正确中断等待锁的线程,必须将获取锁放在外面,然后将InterruptedException抛出 try { System.out.println(thread.getName()+"得到了锁"); long startTime = System.currentTimeMillis(); for( ; ;) { if(System.currentTimeMillis() - startTime >= Integer.MAX_VALUE) break; //插入数据 } } finally { System.out.println(Thread.currentThread().getName()+"执行finally"); lock.unlock(); System.out.println(thread.getName()+"释放了锁"); } } } class MyThread extends Thread { private Test test = null; public MyThread(Test test) { this.test = test; } @Override public void run() { try { test.insert(Thread.currentThread()); } catch (InterruptedException e) { System.out.println(Thread.currentThread().getName()+"被中断"); } } } ~~~ 运行之后,发现thread2能够被正确中断 ## ReadWriteLock ReadWriteLock也是一个接口,在它里面只定义了两个方法