(一)可重入性
可重入性描述这样的一个问题:一个线程在持有一个锁的时候,它内部能否再次(多次)申请该锁。如果一个线程已经获得了锁,其内部还可以多次申请该锁成功。那么我们就称该锁为可重入锁。通过以下伪代码说明:
void methodA(){ lock.lock(); // 获取锁 methodB(); lock.unlock() // 释放锁 } void methodB(){ lock.lock(); // 获取锁 // 其他业务 lock.unlock();// 释放锁 }
可重入锁可以理解为锁的一个标识。该标识具备计数器功能。标识的初始值为0,表示当前锁没有被任何线程持有。每次线程获得一个可重入锁的时候,该锁的计数器就被加1。每次一个线程释放该所的时候,该锁的计数器就减1。前提是:当前线程已经获得了该锁,是在线程的内部出现再次获取锁的场景
大家可以点击加群【JAVA架构知识学习讨论群】473984645,(如多你想跳槽换工作,但是技术又不够,或者工作遇到了瓶颈,我这里有一个Java的免费直播课程,讲的是高端的知识点,只要有1-5年的开发工作经验可以加群找我要课堂链接。)注意:是免费的 没有开发经验的误入。
(二)Lock接口,ReentrantLock说明
2.1 Lock接口说明
2.2 ReentrantLock实现说明
ReentrantLock是Lock接口的一个实现类。为了演示Lock接口的方法,我们以ReentrantLock作为示例说明。
2.2.1 lock(),unlock()方法说明
该demo模拟电影院的售票情况,tickets总票数。开启了10个窗口售票,售完为止
public class ReentrantLockDemo01 implements Runnable { private Lock lock = new ReentrantLock(); private int tickets = 200; @Override public void run() { while (true) { lock.lock(); // 获取锁 try { if (tickets > 0) { TimeUnit.MILLISECONDS.sleep(100); System.out.println(Thread.currentThread().getName() + " " + tickets--); } else { break; } } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); // 释放所 } } } public static void main(String[] args) { ReentrantLockDemo01 reentrantLockDemo = new ReentrantLockDemo01(); for (int i = 0; i < 10; i++) { Thread thread = new Thread(reentrantLockDemo, "thread" + i); thread.start(); } } }
2.2.2 lockInterruptibly()方法说明
从Lock的源码可以看出:lockInterruptibly() 抛出中断异常
void lockInterruptibly() throws InterruptedException;
在synchronize关键字中,同步代码块发送阻塞的情况,例如:wait(),sleep(),jion()等情况下,可以被中断。中断并不意味着线程已经终止
代码示例如下:
public class ReentrantLockDemo02 implements Runnable { private Lock lock = new ReentrantLock(); @Override public void run() { try { lock.lockInterruptibly(); System.out.println(Thread.currentThread().getName() + " running"); Thread.sleep(2000); System.out.println(Thread.currentThread().getName() + " finished"); lock.unlock(); } catch (InterruptedException e) { System.out.println(Thread.currentThread().getName() + " interrupted"); } } public static void main(String[] args) { ReentrantLockDemo02 reentrantLockDemo = new ReentrantLockDemo02(); Thread thread01 = new Thread(reentrantLockDemo, "thread01"); Thread thread02 = new Thread(reentrantLockDemo, "thread02"); thread01.start(); thread02.start(); thread02.interrupt(); } }
输出结果:
thread01 running
thread02 interrupted
thread01 finished
从输出结果可以看出,thread01正常结束程序,thread02被中断程序,执行catch中的代码块
2.2.3 tryLock(),tryLock(long time, TimeUnit unit)方法说明
tryLock()方法立刻返回当前获取情况。
tryLock(long time, TimeUnit unit)等待一定的时间,返回获取情况
public class ReentrantLockDemo03 implements Runnable { private ReentrantLock lock = new ReentrantLock(); @Override public void run() { try { if (lock.tryLock(2, TimeUnit.SECONDS)) { System.out.println(Thread.currentThread().getName() + " 获取当前lock锁"); TimeUnit.SECONDS.sleep(4); } else { System.out.println(Thread.currentThread().getName()+ " 获取锁失败"); } } catch (InterruptedException e) { e.printStackTrace(); } finally { if (lock.isHeldByCurrentThread()) { lock.unlock(); } } } public static void main(String[] args) { ReentrantLockDemo03 reentrantLockDemo = new ReentrantLockDemo03(); Thread thread01 = new Thread(reentrantLockDemo, "thread01"); Thread thread02 = new Thread(reentrantLockDemo, "thread02"); thread01.start(); thread02.start(); } }
2.2.4 newCondition() 方法说明
目前只是对newCondition()使用方式进行说明,没有深入的分析Condition()的实现源码。
Condition的作用是对锁进行更精确的控制。Condition中的await()方法相当于Object的wait()方法,Condition中的signal()方法相当于Object的notify()方法,Condition中的signalAll()相当于Object的notifyAll()方法。不同的是,Object中的wait(),notify(),notifyAll()方法是和”同步锁”(synchronized关键字)捆绑使用的;而Condition是需要与”互斥锁”/”共享锁”捆绑使用的。
Condition的作用是对锁进行更精确的控制。Condition中的await()方法相当于Object的wait()方法,Condition中的signal()方法相当于Object的notify()方法,Condition中的signalAll()相当于Object的notifyAll()方法。不同的是,Object中的wait(),notify(),notifyAll()方法是和”同步锁”(synchronized关键字)捆绑使用的;而Condition是需要与”互斥锁”/”共享锁”捆绑使用的。
public class ProducerConsumerTest { private Lock lock = new ReentrantLock(); private Condition addCondition = lock.newCondition(); private Condition removeCondition = lock.newCondition(); private LinkedList<Integer> resources = new LinkedList<>(); private int maxSize; public ProducerConsumerTest(int maxSize) { this.maxSize = maxSize; } public class Producer implements Runnable { private int proSize; private Producer(int proSize) { this.proSize = proSize; } @Override public void run() { lock.lock(); try { for (int i = 1; i < proSize; i++) { while (resources.size() >= maxSize) { System.out.println("当前仓库已满,等待消费..."); try { addCondition.await(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("已经生产产品数: " + i + "\t现仓储量总量:" + resources.size()); resources.add(i); removeCondition.signal(); } } finally { lock.unlock(); } } } public class Consumer implements Runnable { @Override public void run() { String threadName = Thread.currentThread().getName(); while (true) { lock.lock(); try { while (resources.size() <= 0) { System.out.println(threadName + " 当前仓库没有产品,请稍等..."); try { // 进入阻塞状态 removeCondition.await(); } catch (InterruptedException e) { e.printStackTrace(); } } // 消费数据 int size = resources.size(); for (int i = 0; i < size; i++) { Integer remove = resources.remove(); System.out.println(threadName + " 当前消费产品编号为:" + remove); } // 唤醒生产者 addCondition.signal(); } finally { lock.unlock(); } } } } public static void main(String[] args) throws InterruptedException { ProducerConsumerTest producerConsumerTest = new ProducerConsumerTest(10); Producer producer = producerConsumerTest.new Producer(100); Consumer consumer = producerConsumerTest.new Consumer(); final Thread producerThread = new Thread(producer, "producer"); final Thread consumerThread = new Thread(consumer, "consumer"); producerThread.start(); TimeUnit.SECONDS.sleep(2); consumerThread.start(); } }
我这儿整理了比较全面的JAVA相关的面试资料,
需要领取面试资料的同学,请加群:473984645
今天的文章可重入锁:ReentrantLock理解使用分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/55508.html