Java多线程(五) ReentrantLock、Lock和Condition的用法

Java多线程(五) ReentrantLock、Lock和Condition的用法


ReentrantLock类:

ReentrantLock是一个可重入的互斥锁,ReentrantLock由最近成功获取锁,还没有释放的线程所拥有,当锁被另一个线程拥有时,调用lock的线程可以成功获取锁。如果锁已经被当前线程拥有,当前线程会立即返回。此类的构造方法提供一个可选的公平参数

  1. public ReentrantLock(boolean fair) {
  2. sync = fair ? new FairSync() : new NonfairSync();
  3. }  

公平与非公平有何区别,所谓公平就是严格按照FIFO顺序获取锁,非公平安全由程序员自己设计,比如可以按优先级,也可以按运行次数等规则来选择。


实例如下:

Bank类如下:

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;


public class Bank {
// private ReentrantLock myLock = new ReentrantLock();// 互斥锁 Lock
// Lock 实现提供了比使用 synchronized
// 方法和语句可获得的更广泛的锁定操作。此实现允许更灵活的结构,可以具有差别很大的属性,可以支持多个相关的 Condition 对象。
private Lock myLock;
// Condition: 条件(也称为条件队列 或条件变量)为线程提供了一个含义,以便在某个状态条件现在可能为 true
// 的另一个线程通知它之前,一直挂起该线程(即让其“等待”)。因为访问此共享状态信息发生在不同的线程中,所以它必须受保护,因此要将某种形式的锁与该条件相关联。等待提供一个条件的主要属性是:以原子方式
// 释放相关的锁,并挂起当前线程,就像 Object.wait 做的那样。
private Condition sufficientFunds;
private final double[] accounts;


public Bank(int n, double initialBalance) {
accounts = new double[n];
for (int i = 0; i < accounts.length; i++)
accounts[i] = initialBalance;
// ReentrantLock()构建一个可以被用来保护临界区的可重入锁
// ReentrantLock(boolean fair)
// 构建一个带有公平策略的锁。一个公平锁偏爱等待时间最长的线程。但是这个公平的保证将大大降低性能。所以,默认情况下,锁没有强制为公平的
myLock = new ReentrantLock();// 创建互斥锁
sufficientFunds = myLock.newCondition();// newCondition() 返回绑定到此 Lock
// 实例的新 Condition 实例。
// 返回一个与该锁相关的条件对象
}


public void transfer(int from, int to, double amount) {
myLock.lock();// lock()获取这个锁,如果锁同时被另一个线程拥有则发生阻塞
try {
while (accounts[from] < amount)
sufficientFunds.await();// 将该线程放到条件的等待集中
System.out.print(Thread.currentThread());
accounts[from] -= amount;
System.out.printf(" %10.2f from %d to %d", amount, from, to);
accounts[to] += amount;
System.out.printf(" Total Balance: %10.2f%n", getTotalBalance());
sufficientFunds.signalAll();// 解除该条件的等待集中的所有线程的阻塞状态
// sufficientFunds.signal();//从该条件的等待集中随机第选择一个线程,解除其阻塞状态
} catch (Exception e) {
myLock.unlock();// unlock()释放这个锁
}
}


public double getTotalBalance() {
myLock.lock();
double sum = 0;
try {
for (double a : accounts)
sum += a;
} catch (Exception e) {
myLock.unlock();
}
return sum;
}


public int size() {
return accounts.length;
}


}


TransferRunnable类如下:

public class TransferRunnable implements Runnable {
private int fromAccount;
private double maxAmount;
private int DELAY = 10;
private Bank bank;


public TransferRunnable(Bank bank, int fromAccount, double maxAmount) {
this.bank = bank;
this.fromAccount = fromAccount;
this.maxAmount = maxAmount;
}


public void run() {

try {
while (true) {
int toAccount = (int) (bank.size() * Math.random());
double amount = maxAmount * Math.random();
bank.transfer(fromAccount, toAccount, amount);
Thread.sleep((int) (DELAY * Math.random()));
}
} catch (InterruptedException e) {
}
}


}


测试类UnsynchBankTest 如下:

public class UnsynchBankTest {
public static final int NACCOUNTS = 100;
public static final double INITIAL_BALANCE = 1000;


public static void main(String[] args) {
Bank b = new Bank(NACCOUNTS, INITIAL_BALANCE);
int i;
for (i = 0; i < NACCOUNTS; i++) {
TransferRunnable r = new TransferRunnable(b, i, INITIAL_BALANCE);
Thread t = new Thread(r);
t.start();
}
}
}


运行结果如下:

Thread[Thread-1,5,main]       0.01 from 1 to 34 Total Balance:  100000.00
Thread[Thread-1,5,main]      19.60 from 1 to 98 Total Balance:  100000.00
Thread[Thread-1,5,main]     879.09 from 1 to 92 Total Balance:  100000.00
Thread[Thread-0,5,main]     840.53 from 0 to 25 Total Balance:  100000.00
Thread[Thread-4,5,main]     870.95 from 4 to 82 Total Balance:  100000.00
Thread[Thread-2,5,main]     658.99 from 2 to 17 Total Balance:  100000.00
Thread[Thread-3,5,main]     449.57 from 3 to 4 Total Balance:  100000.00
Thread[Thread-3,5,main]     123.89 from 3 to 84 Total Balance:  100000.00
Thread[Thread-3,5,main]      38.94 from 3 to 80 Total Balance:  100000.00


下面对这些知识点做个总结:

使用Lock和Condition对象,记住他们的关键之处:

1、锁用来保护代码片段,任何时刻只能有一个线程执行被保护的代码。

2、锁可以管理试图进入被保护代码段的线程。

3、锁可以拥有一个或多个相关的条件对象。

4、每个条件对象管理那些已经进入被保护的代码段但还不能运行的线程。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值