JAVA中ReentrantLock详解(转)

转自https://www.cnblogs.com/java-learner/p/9651675.html

前言:本文解决的问题

  • 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接口有哪些方法
lock
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; } } 

执行结果
reentrantLOck执行结果

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

转载于:https://www.cnblogs.com/ffaiss/p/11431428.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ReentrantLockJava的一种可重入互斥锁,它具有与同步代码块相同的基本行为和语义。下面是ReentrantLock使用样例: ```java import java.util.concurrent.locks.ReentrantLock; public class LockExample { private final ReentrantLock lock = new ReentrantLock(); private int count = 0; public void increment() { lock.lock(); try { count++; } finally { lock.unlock(); } } public int getCount() { lock.lock(); try { return count; } finally { lock.unlock(); } } public static void main(String[] args) { LockExample example = new LockExample(); Thread thread1 = new Thread(() -> { for (int i = 0; i < 100000; i++) { example.increment(); } }); Thread thread2 = new Thread(() -> { for (int i = 0; i < 100000; i++) { example.increment(); } }); thread1.start(); thread2.start(); try { thread1.join(); thread2.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Count is: " + example.getCount()); } } ``` 在上面的例子,我们使用ReentrantLock来保护一个共享计数器。我们使用lock.lock()和lock.unlock()方法来获取和释放锁。在increment()和getCount()方法,我们都使用了lock.lock()和lock.unlock()方法,以确保这些方法可以互斥地执行。 需要注意的是,当使用ReentrantLock时,必须在finally块调用lock.unlock()方法,以确保锁在所有情况下都被释放,即使在代码出现异常。否则,锁可能被一直持有,从而导致死锁或死循环等问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值