ReentrantLock简称可重入的互斥锁,当一个线程多次获取它所占有的锁资源时,是可以成功的,每当成功获取一次的时候,其保持计数将会+1,并且在其执行完毕释放锁的时候,保持计数随之清零;至于互斥的概念,就是当一个线程持有该锁时,其他需要获取该锁的线程将一直等待直至该锁被释放;这是多线程中实现同步的一种方式,它实现了synchronized的基本功能,同时也拓展了一些新的方法。
synchronized和ReentrantLock的区别:
除了synchronized的功能,多了三个高级功能:等待可中断,公平锁,绑定多个Condition.
1.等待可中断
在持有锁的线程长时间不释放锁的时候,等待的线程可以选择放弃等待. tryLock(long timeout, TimeUnit unit)
2.公平锁
按照申请锁的顺序来一次获得锁称为公平锁.synchronized的是非公平锁,ReentrantLock可以通过构造函数实现公平锁. new RenentrantLock(boolean fair)
3.绑定多个Condition
通过多次newCondition可以获得多个Condition对象,可以简单的实现比较复杂的线程同步的功能.通过await(),signal();
- 首先声明一个银行卡的辅助类
package com.test.demo; public class BankCard { private String cardNo; private int balance; public String getCardNo() { return cardNo; } public void setCardNo(String cardNo) { this.cardNo = cardNo; } public int getBalance() { return balance; } public void setBalance(int balance) { this.balance = balance; } }
- 创建Husband类执行存钱操作
package com.test.demo; import java.util.concurrent.locks.Lock; public class Husband implements Runnable{ private BankCard card; private Lock lock; public Husband(BankCard card, Lock lock){ this.card = card; this.lock = lock; } public void run() { while(true){ lock.lock(); System.out.println("丈夫准备存钱,账户余额为: "+ card.getBalance()); card.setBalance(card.getBalance() + 500); System.out.println("丈夫存钱完毕,账户余额为: " + card.getBalance()); lock.unlock(); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } } }
- 创建Wife类执行消费操作
package com.test.demo; import java.util.concurrent.locks.Lock; public class Wife implements Runnable{ private BankCard card; private Lock lock; public Wife(BankCard card, Lock lock){ this.card = card; this.lock = lock; } public void run() { while(true){ lock.lock(); System.out.println("妻子要消费,账户余额为: "+ card.getBalance()); card.setBalance(card.getBalance() - 1000); System.out.println("妻子消费完毕,账户余额为:" +card.getBalance()); lock.unlock(); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } } }
- 启动线程进行测试
package com.test.demo; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * Hello world! * */ public class App { public static void main( String[] args ) { BankCard card = new BankCard(); card.setBalance(10000); Lock lock = new ReentrantLock(); Wife child = new Wife(card, lock); Husband father = new Husband(card, lock); new Thread(child).start(); new Thread(father).start(); } }
运行效果如下,我们可以看到正常操作
丈夫准备存钱,账户余额为: 10000 丈夫存钱完毕,账户余额为: 10500 妻子要消费,账户余额为: 10500 妻子消费完毕,账户余额为:9500 妻子要消费,账户余额为: 9500 妻子消费完毕,账户余额为:8500 丈夫准备存钱,账户余额为: 8500 丈夫存钱完毕,账户余额为: 9000 妻子要消费,账户余额为: 9000 妻子消费完毕,账户余额为:8000 丈夫准备存钱,账户余额为: 8000 丈夫存钱完毕,账户余额为: 8500 丈夫准备存钱,账户余额为: 8500 丈夫存钱完毕,账户余额为: 9000 妻子要消费,账户余额为: 9000 妻子消费完毕,账户余额为:8000
- 当妻子锁定后不释放锁
package com.test.demo; import java.util.concurrent.locks.Lock; public class Wife implements Runnable{ private BankCard card; private Lock lock; public Wife(BankCard card, Lock lock){ this.card = card; this.lock = lock; } public void run() { while(true){ lock.lock(); System.out.println("妻子要消费,账户余额为: "+ card.getBalance()); card.setBalance(card.getBalance() - 1000); System.out.println("妻子消费完毕,账户余额为:" +card.getBalance()); //lock.unlock(); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } } }
运行效果如下:
妻子要消费,账户余额为: 10000 妻子消费完毕,账户余额为:9000 妻子要消费,账户余额为: 9000 妻子消费完毕,账户余额为:8000 妻子要消费,账户余额为: 8000 妻子消费完毕,账户余额为:7000 妻子要消费,账户余额为: 7000 妻子消费完毕,账户余额为:6000 妻子要消费,账户余额为: 6000 妻子消费完毕,账户余额为:5000 妻子要消费,账户余额为: 5000 妻子消费完毕,账户余额为:4000 妻子要消费,账户余额为: 4000 妻子消费完毕,账户余额为:3000 妻子要消费,账户余额为: 3000 妻子消费完毕,账户余额为:2000 妻子要消费,账户余额为: 2000 妻子消费完毕,账户余额为:1000
可以看到获取不到锁的Husband线程将一直处于阻塞状态!
除此之外,ReentrantLock提供了灵活的中断机制,第一种:ReentrantLock尝试获取锁时,可以指定等待的时间,当超过等待时间后则放弃执行并返回一个boolean值;第二种:ReentrantLock提供了可中断锁操作。
try { if (lock.tryLock(5, TimeUnit.SECONDS)) { //如果已经被lock,尝试等待5s,看是否可以获得锁,如果5s后仍然无法获得锁则返回false继续执行 try { //操作 } finally { lock.unlock(); } } } catch (InterruptedException e) { e.printStackTrace(); //当前线程被中断时(interrupt),会抛InterruptedException }
以上为本次的简单演示,仅仅供个人的学习所用!
相关推荐
java语言 并发编程 ReentrantLock与synchronized区别 详解
助于理解的例子 博文链接:https://uule.iteye.com/blog/1488356
深入java并发编程,使用ReentrantLock和 Synchronized加锁
ReentrantLock与synchronized来的区别 1.synchronized是独占锁,加锁和解锁的过程自动进行,易于操作,但不够灵活。ReentrantLock也是独占锁,加锁和解锁的过程需要手动进行,不易操作,但非常灵活。 2.synchronized...
java lock synchronized
第15讲丨synchronized和ReentrantLock有什么区别呢?.html
在 Java 5 以前,synchronized 是仅有的同步手段,在代码中, synchronized 可以用来修饰方法,也可以使用在特定的代码块儿上,本质上
重入锁ReentrantLock 相对来说是synchronized、Object.wait()和Object.notify()方法的替代品(或者说是增强版),在JDK5.0的早期版本,重入锁的性能远远好于synchronized,但从JDK6.0开始,JDK在synchronized上做了...
synchronized关键字是通过字节码指令来实现的 synchronized关键字编译后会在同步块前后形成monitorenter和monitorexit两个字节码指令 执行monitorenter指令时需要先获得对象的锁(每个对象有一个监视器锁...
背景,应该就是Synchronized的缺点Synchronized产生原因,原子性(Atomicity)与可见性(visibility),其中可见性涉及到JM
Locks 框架提供了比传统的 synchronized 关键字更强大、更灵活的线程同步机制,而 ReentrantLock 是其中的一种重要实现。 Locks 框架概述: 简要介绍 Locks 框架,解释其在多线程编程中的作用和优势。比较 Locks ...
本文介绍了多线程和并发性并不是什么新内容,但是Java语言设计中的创新之一就是,它是第一个直接把跨平台...本文还简单介绍和比较了ReentrantLock和synchronized,以及在什么时候选择用ReentrantLock代替synchronized。
ReentrantLock的使用及注意事项
在java关键字synchronized隐式支持重入性(关于synchronized可以看这篇文章),synchronized通过获取自增,释放自减的方式实现重入。与此同时,ReentrantLock还支持公平锁和非公平锁两种方式。 那么,要想完完全全的...
1、ReentrantLock简介 2、ReentrantLock函数列表 3、重入的实现 4、公平锁与非公平锁 5、ReentrantLock 扩展的功能 6
ReentrantLock源码剖析
目录: 简介 ReentrantLock的基本用法 2.1 创建ReentrantLock 2.2 获取锁和释放锁 公平性与非公平性 3.1 公平锁 3.2 非公平锁 中断响应 ...ReentrantLock与synchronized的对比 最佳实践与注意事项
一张图将整个ReentrantLock流程看懂,干货满满 一张图将整个ReentrantLock流程看懂,干货满满 一张图将整个ReentrantLock流程看懂,干货满满 一张图将整个ReentrantLock流程看懂,干货满满 一张图将整个...
synchronized 和 ReentrantLock 也是高频的面试问题,我们这篇文章就来深入学习一下。 synchronized 和 ReentrantLock 是如何实现的?它们有什么区别? synchronized是独占式悲观锁,是通过JVM 层面实现的,...