java的reentrantlock_JAVA中ReentrantLock详解

前言:本文解决的问题

RentrantLock与Synchronized区别

ReentrantLock特征

ReentrantLock类的方法介绍

1.什么是ReentrantLock

1.1ReentrantLock 与Synchronized区别

在面试中询问ReentrantLock与Synchronized区别时,一般回答都是

ReentrantLock

ReentrantLock是JDK方法,需要手动声明上锁和释放锁,因此语法相对复杂些;如果忘记释放锁容易导致死锁

ReentrantLock具有更好的细粒度,可以在ReentrantLock里面设置内部Condititon类,可以实现分组唤醒需要唤醒的线程

RenentrantLock能实现公平锁

Synchronized

Synchoronized语法上简洁方便

Synchoronized是JVM方法,由编辑器保证枷锁和释放

1.2ReentrantLock特征介绍

JAVA的java.util.concurrent框架中提供了ReentrantLock类(于JAVA SE 5.0时引入),ReentrantLock实现了lock接口,具体在JDK中的定义如下:

public class ReentrantLock implements Lock, java.io.Serializable {

public ReentrantLock() {

sync = new NonfairSync();

}

/**

* Creates an instance of {@code ReentrantLock} with the

* given fairness policy.

*

* @param fair {@code true} if this lock should use a fair ordering policy

*/

public ReentrantLock(boolean fair) {

sync = fair ? new FairSync() : new NonfairSync();

}

}

看到一个类首先就需要知道它的构造方法有哪些,ReentrantLock有两个构造方法,一个是无参的 ReentrantLock() ;另一个含有布尔参数public ReentrantLock(boolean fair)。后面一个构造函数说明ReentrantLock可以新建公平锁;而Synchronized只能建立非公平锁。

那么Lock接口有哪些方法

8031577c1ff95a7f4e292c3baebd0fa4.png

Lock接口中有lock和unlock方法,还有newCondition() 方法,这就是上面说的ReentrantLock里面设置内部Condititon类。由于ReentrantLock实现了Lock接口,因此它必须实现该方法,具体如下:

public Condition newCondition() {

return sync.newCondition();

}

返回Condition类的一个实例。

2 ReentrantLock其它方法介绍

在介绍它的其它方法前,要先明白它的使用方法,以下JDK中的建议:

class X {

private final ReentrantLock lock = new ReentrantLock();

// ...

public void m() {

lock.lock(); // block until condition holds

try {

// ... method body

} finally {

lock.unlock()

}

}

建议用try,在finally里面一定要释放锁,防止被中断时锁没释放,造成死锁

lock()

public void lock() {

sync.lock();

}

如果该锁没被其它线程获得,则立即返回;并且把 lock hold count的值变位1.

unlock()

public void unlock() {

sync.release(1);

}

如果当前线程是该锁的持有者,则保持计数递减。 如果保持计数现在为零,则锁定被释放。 如果当前线程不是该锁的持有者,则抛出IllegalMonitorStateException 。

isFair()

public final boolean isFair() {

return sync instanceof FairSync;

}

判断该锁是不是公平锁

newCondition()

public Condition newCondition() {

return sync.newCondition();

}

返回新的ConditionObject对象。

Condition接口中的方法

await(): void await() throws InterruptedException;

Condition接口中的方法,导致当前线程等到发信号。

siginal()

/**

* Moves the longest-waiting thread, if one exists, from the

* wait queue for this condition to the wait queue for the

* owning lock.

*

* @throws IllegalMonitorStateException if {@link #isHeldExclusively}

* returns {@code false}

*/

public final void signal() {

if (!isHeldExclusively())

throw new IllegalMonitorStateException();

Node first = firstWaiter;

if (first != null)

doSignal(first);

}

唤醒一个等待该条件的线程去获得锁(第一个)。

signalAll():唤醒所有等待线程。

3 ReentrantLock完整实例介绍

package chapter10.reentrantlock;

import java.util.Arrays;

import java.util.concurrent.locks.Condition;

import java.util.concurrent.locks.Lock;

import java.util.concurrent.locks.ReentrantLock;

/*模拟转账,把钱从一个账户转到另一个账户

* */

public class ReentrantLockUse {

public static final int NACCOUNTS = 100;

public static final double INITIAL_BALANCE = 1000;

public static final double MAX_AMOUNT = 1000;

public static final int DELAY = 10;

public static void main(String[] args) {

Bank bank = new Bank(NACCOUNTS,INITIAL_BALANCE);

for(int i = 0 ; i < NACCOUNTS ; i++) {

int fromAccount = i ;

Runnable r = () ->{//lambda表达式

try {

while(true) {

int toAccount = (int) (bank.size()*Math.random());

double amount = MAX_AMOUNT * Math.random();

bank.transfer(fromAccount, toAccount, amount);

Thread.sleep((int)(DELAY*Math.random()));

}

}

catch(InterruptedException e) {

}

};

Thread t = new Thread(r);//新建线程

t.start();

}

}

}

class Bank{

private final double[] account;//账户

private Lock bankLock ; //重复锁

private Condition sufficientFunds;//条件对象

public Bank(int n, double initialBalance) {

account = new double[n];

Arrays.fill(account, initialBalance);

bankLock = new ReentrantLock(); //构造对象时,实例化锁

sufficientFunds = bankLock.newCondition();//新建条件对象

}

/*转账,把from账户里面的钱转到to里面,金额是amount*/

public void transfer(int from , int to,double amount) {

bankLock.lock();

try {

while(account[from] < amount) {

sufficientFunds.await();

}

System.out.println(Thread.currentThread());

account[from] -=amount;

System.out.printf("%10.2f from %d to %d ",amount,from,to);

account[to] +=amount;

System.out.printf(" Total Balance : %10.2f%n", getTotalBalance());

sufficientFunds.signalAll();

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

finally {

bankLock.unlock();

}

}

/*做的所有账户总额*/

public double getTotalBalance() {

bankLock.lock();

try {

double sum = 0;

for(double a : account) {

sum +=a;

}

return sum;

}

finally {

bankLock.unlock();

}

}

public int size() {

return account.length;

}

}

执行结果

96e599f9bbf2877ca619aca1fdfec391.png

结果分析

循环建立100个线程,每个线程都在不停转账,由于ReentrantLock的使用,任何时刻所有账户的总额都保持不变。另外,把钱amount从A账户转到B账户,要先判断A账户中是否有这么多钱,不过没有就调用条件对象ConditionObject中的await()方法,放弃该线程,等该其它线程转钱进来;转钱完成后调用.siginalAll()。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值