使用ReentrantLock的实例
一、实例简介:
本例子是典型的多线程竞争的范例:两个银行职员同时操作同一账号。本人分别使用不加任何控制、使用ReentrantLock、使用synchronized的三种方式实现,并比较其结果。
二、类列表:
|
类名 |
功能 |
|
Account |
银行账号类 |
|
Bank |
银行类:定义调用操作账号的事务方法 |
|
BankWithSync |
银行类:使用synchronized定义调用操作账号的事务方法 |
|
Transaction |
账号事务类:定义入账/出账等对银行账号的操作 |
|
Clerk |
银行职员类:使用Bank类作为构造方法的参数,实现了Runnable接口,按照事务类型对银行账号进行入账/出账操作(不使用锁) |
|
ClerkWithSync |
银行职员类:使用BankWithSync类作为构造方法的参数,实现了Runnable接口,按照事务类型对银行账号进行入账/出账操作 |
|
ClerkWithLock |
银行职员类:使用Bank类作为构造方法的参数,实现了Runnable接口,按照事务类型对银行账号进行入账/出账操作(使用ReentrantLock) |
|
multiClerkConcurrentTransaction |
提供调用简介中的三种方式实现两个银行职员同时操作同一账号。 operationWithUnuseLock-未使用锁进行账号的事务操作 operationWithReentrantLock-使用可重入锁进行账号的事务操作 operationWithSynchronized-使用synchronized进行账号的事务操作 |
其中operationWithUnuseLock主要使用了: Clerk类和Bank类;
operationWithReentrantLock主要使用了: ClerkWithLock类和Bank类。
operationWithSynchronized主要使用了: ClerkWithSync类和BankWithSync类。
运行结果:
初始存款:$500
入账金额:$856
出账金额:$888
最终存款:$-22
应为 :$468
未使用锁花费6480ms
初始存款:$500
入账金额:$841
出账金额:$878
最终存款:$463
应为 :$463
使用Reentrant锁花费6639ms
初始存款:$500
入账金额:$832
出账金额:$873
最终存款:$459
应为 :$459
使用synchornized同步花费6249ms
三、源代码:
/*
* Account.java
*
* Created on 2005年1月25日, 下午3:15
*/
package bjInfoTech.util.threadManage.concurrent.tryIt.bank;
/**
* 定义银行账户类
* @author 聪明的猪
*/
public class Account {
private int balance;
private int accountNumber;
/**
* 银行账户构造方法
* @param accountNumber 用户帐号
* @param balance 帐号余额
*/
public Account(int accountNumber,int balance) {
this.accountNumber=accountNumber;
this.balance=balance;
}
/**
* 返回帐号余额
* @return 帐号余额
*/
public int getBalance(){
return balance;
}
/**
* 赋值帐号余额
* @param balance 余额
*/
public void setBalance(int balance){
this.balance=balance;
}
/**
* 返回银行帐号
* @return 银行帐号
*/
public int getAccountNumber(){
return accountNumber;
}
public String toString(){
return "No."+accountNumber+" :$"+balance;
}
}
/*
* Bank.java
*
* Created on 2005年1月25日, 下午3:54
*/
package bjInfoTech.util.threadManage.concurrent.tryIt.bank;
import bjInfoTech.util.threadManage.concurrent.tryIt.bank.*;
/**
* 银行类,主要执行事务
* @author 聪明的猪
*/
public class Bank {
/** Creates a new instance of Bank */
public Bank() {
}
/**
* 执行事务,按照事务的类型对用户帐号的余额进行操作。
* @param transaction transaction对象
*/
public void doTransaction(Transaction transaction){
int balance=transaction.getAccount().getBalance();
switch(transaction.getTransactionType()){
case Transaction.CREDIT:
try{
Thread.sleep(100);
}
catch(InterruptedException e){
System.out.println(e);
}
balance+=transaction.getAmount();
break;
case Transaction.DEBIT:
try{
Thread.sleep(150);
}
catch(InterruptedException e){
System.out.println(e);
}
balance-=transaction.getAmount();
break;
default:
System.out.println("无效的事务");
System.exit(1);
}
transaction.getAccount().setBalance(balance);
}
}
/*
* BankWithSync.java
*
* Created on 2005年1月25日, 下午3:54
*/
package bjInfoTech.util.threadManage.concurrent.tryIt.bank;
import bjInfoTech.util.threadManage.concurrent.tryIt.bank.*;
/**
* 银行类,主要执行事务(使用synchronized同步)
* @author 聪明的猪
*/
public class BankWithSync {
/** Creates a new instance of Bank */
public BankWithSync() {
}
/**
* 执行事务,按照事务的类型对用户帐号的余额进行操作(使用synchronized同步)。
* @param transaction transaction对象
*/
synchronized public void doTransaction(Transaction transaction){
int balance=transaction.getAccount().getBalance();
switch(transaction.getTransactionType()){
case Transaction.CREDIT:
try{
Thread.sleep(100);
}
catch(InterruptedException e){
System.out.println(e);
}
balance+=transaction.getAmount();
break;
case Transaction.DEBIT:
try{
Thread.sleep(150);
}
catch(InterruptedException e){
System.out.println(e);
}
balance-=transaction.getAmount();
break;
default:
System.out.println("无效的事务");
System.exit(1);
}
transaction.getAccount().setBalance(balance);
}
}
/*
* Clerk.java
*
* Created on 2005年1月25日, 下午4:01
*/
package bjInfoTech.util.threadManage.concurrent.tryIt.bank;
import bjInfoTech.util.threadManage.concurrent.tryIt.bank.*;
/**
* 定义银行职员类(没使用锁)
* @author 聪明的猪
*/
public class Clerk implements Runnable{
private Bank theBank;
private Transaction inTray;
/**
* 构造银行职员类
* @param theBank 银行类对象
*/
public Clerk(Bank theBank) {
this.theBank=theBank;
inTray=null;
}
/**
* 银行职员执行事务
* @param transaction 事务类对象
*/
public void doTransaction(Transaction transaction){
inTray=transaction;
}
/**
* 线程的run方法
*/
public void run(){
while(true){
while(inTray==null){
try{
Thread.sleep(150);
}
catch(InterruptedException e){
System.out.println(e);
}
}
theBank.doTransaction(inTray);
inTray=null;
}
}
/**
* 返回职员是否忙碌
* @return 如果职员忙碌,则返回true;否则返回false。
*/
public boolean isBusy(){
return inTray!=null;
}
}
/*
* ClerkWithLock.java
*
* Created on 2005年1月25日, 下午4:01
*/
package bjInfoTech.util.threadManage.concurrent.tryIt.bank;
import bjInfoTech.util.threadManage.concurrent.tryIt.bank.*;
import edu.emory.mathcs.backport.java.util.concurrent.locks.*;
import edu.emory.mathcs.backport.java.util.concurrent.*;
/**
* 定义银行职员类(使用ReenTrantLock)
* @author 聪明的猪
*/
public class ClerkWithLock implements Runnable{
private Bank theBank;
private Transaction inTray;
private ReentrantLock lock;
/**
* 构造银行职员类
* @param theBank 银行类对象
* @param lock 可重入的锁对象
*/
public ClerkWithLock(Bank theBank,ReentrantLock lock) {
this.theBank=theBank;
this.lock=lock;
inTray=null;
}
/**
* 银行职员执行事务(使用ReentrantLock同步)
* @param transaction 事务类对象
*/
public void doTransaction(Transaction transaction){
inTray=transaction;
}
/**
* 线程的run方法
*/
public void run(){
while(true){
while(inTray==null){
try{
Thread.sleep(150);
}
catch(InterruptedException e){
System.out.println(e);
}
}
try{
lock.lockInterruptibly();
theBank.doTransaction(inTray);
inTray=null;
lock.unlock();
}
catch(InterruptedException e){
if (lock.isHeldByCurrentThread()){
lock.unlock();
}
System.out.println(e);
}
}
}
/**
* 返回职员是否忙碌
* @return 如果职员忙碌,则返回true;否则返回false。
*/
public boolean isBusy(){
return inTray!=null;
}
}
/*
* ClerkWithSync.java
*
* Created on 2005年1月25日, 下午4:01
*/
package bjInfoTech.util.threadManage.concurrent.tryIt.bank;
import bjInfoTech.util.threadManage.concurrent.tryIt.bank.*;
/**
* 定义银行职员类(Bank的事务方法使用synchronized同步)
* @author 聪明的猪
*/
public class ClerkWithSync implements Runnable{
private BankWithSync theBank;
private Transaction inTray;
/**
* 构造银行职员类(Bank的事务方法使用synchronized同步)
* @param theBank 银行类对象
*/
public ClerkWithSync(BankWithSync theBank) {
this.theBank=theBank;
inTray=null;
}
/**
* 银行职员执行事务
* @param transaction 事务类对象
*/
public void doTransaction(Transaction transaction){
inTray=transaction;
}
/**
* 线程的run方法
*/
public void run(){
while(true){
while(inTray==null){
try{
Thread.sleep(150);
}
catch(InterruptedException e){
System.out.println(e);
}
}
theBank.doTransaction(inTray);
inTray=null;
}
}
/**
* 返回职员是否忙碌
* @return 如果职员忙碌,则返回true;否则返回false。
*/
public boolean isBusy(){
return inTray!=null;
}
}
/*
* Transaction.java
*
* Created on 2005年1月25日, 下午3:13
*/
package bjInfoTech.util.threadManage.concurrent.tryIt.bank;
/**
* 银行事务类
* @author 聪明的猪
*/
public class Transaction {
public static final int DEBIT=0;
public static final int CREDIT=1;
public static String[] types={"Debit","Credit"};
private Account account;
private int amount;
private int transactionType;
/**
* 事务类的构造方法
* @param account 银行账户
* @param transactionType 事务类型(入账/出账)
* @param amount 入账/出账金额
*/
public Transaction(Account account,int transactionType,int amount){
this.account=account;
this.transactionType=transactionType;
this.amount=amount;
}
/**
* 返回用户帐号类
* @return 用户帐号类
*/
public Account getAccount(){
return account;
}
/**
* 返回事务类型
* @return 事务类型字符串
*/
public int getTransactionType(){
return transactionType;
}
/**
* 返回操作金额
* @return 操作金额
*/
public int getAmount(){
return amount;
}
public String toString(){
return types[transactionType]+": "+":$"+amount;
}
}
/*
* multiClerkConcurrentTransaction.java
*
* Created on 2005年1月25日, 下午4:10
*/
package bjInfoTech.util.threadManage.concurrent.tryIt.bank;
import bjInfoTech.util.threadManage.concurrent.tryIt.bank.*;
import edu.emory.mathcs.backport.java.util.concurrent.locks.*;
import java.util.Random;
/**
* 多个银行职员并发访问同一银行账号
* @author 聪明的猪
*/
public class multiClerkConcurrentTransaction {
/** Creates a new instance of multiClerkConcurrentTransaction */
public multiClerkConcurrentTransaction() {
}
/**
* 未使用锁进行账号的事务操作
*/
public static void operationWithUnuseLock(){
int initialBalance=500;
int totalCredits=0;
int totalDebits=0;
int transactionCount=20;
Bank theBank=new Bank();
Clerk clerk1=new Clerk(theBank);
Clerk clerk2=new Clerk(theBank);
Account account=new Account(1,initialBalance);
Thread clerk1Thread=new Thread(clerk1);
Thread clerk2Thread=new Thread(clerk2);
clerk1Thread.setDaemon(true);
clerk2Thread.setDaemon(true);
clerk1Thread.start();
clerk2Thread.start();
Random rand=new Random();
Transaction transaction;
int amount=0;
//职员1和职员2共进行20次事务操作
for(int i=1;i<=transactionCount;i++){
//职员1入账amount元
transaction=new Transaction(account,Transaction.CREDIT,amount);
totalCredits+=amount;
while(clerk1.isBusy()){
try{
Thread.sleep(25);
}
catch(InterruptedException e){
System.out.println(e);
}
}
clerk1.doTransaction(transaction);
//职员2出账amount元
amount=30+rand.nextInt(31);
transaction=new Transaction(account,Transaction.DEBIT,amount);
totalDebits+=amount;
while(clerk2.isBusy()){
try{
Thread.sleep(25);
}
catch(InterruptedException e){
System.out.println(e);
}
}
clerk2.doTransaction(transaction);
}
//等待两职员工作结束
while(clerk1.isBusy()||clerk2.isBusy()){
try{
Thread.sleep(25);
}
catch(InterruptedException e){
System.out.println(e);
}
}
//打印结果
System.out.println(
"初始存款:$"+initialBalance+"/n"+
"入账金额:$"+totalCredits+"/n"+
"出账金额:$"+totalDebits+"/n"+
"最终存款:$"+account.getBalance()+"/n"+
"应为 :$"+(initialBalance+totalCredits-totalDebits));
}
/**
* 使用可重入锁进行账号的事务操作
*/
public static void operationWithReentrantLock(){
int initialBalance=500;
int totalCredits=0;
int totalDebits=0;
int transactionCount=20;
ReentrantLock lock=new ReentrantLock();
Bank theBank=new Bank();
ClerkWithLock clerk1=new ClerkWithLock(theBank,lock);
ClerkWithLock clerk2=new ClerkWithLock(theBank,lock);
Account account=new Account(1,initialBalance);
Thread clerk1Thread=new Thread(clerk1);
Thread clerk2Thread=new Thread(clerk2);
clerk1Thread.setDaemon(true);
clerk2Thread.setDaemon(true);
clerk1Thread.start();
clerk2Thread.start();
Random rand=new Random();
Transaction transaction;
int amount=0;
//职员1和职员2共进行20次事务操作
for(int i=1;i<=transactionCount;i++){
//职员1入账amount元
transaction=new Transaction(account,Transaction.CREDIT,amount);
totalCredits+=amount;
while(clerk1.isBusy()){
try{
Thread.sleep(25);
}
catch(InterruptedException e){
System.out.println(e);
}
}
clerk1.doTransaction(transaction);
//职员2出账amount元
amount=30+rand.nextInt(31);
transaction=new Transaction(account,Transaction.DEBIT,amount);
totalDebits+=amount;
while(clerk2.isBusy()){
try{
Thread.sleep(25);
}
catch(InterruptedException e){
System.out.println(e);
}
}
clerk2.doTransaction(transaction);
}
//等待两职员工作结束
while(clerk1.isBusy()||clerk2.isBusy()){
try{
Thread.sleep(25);
}
catch(InterruptedException e){
System.out.println(e);
}
}
//打印结果
System.out.println(
"初始存款:$"+initialBalance+"/n"+
"入账金额:$"+totalCredits+"/n"+
"出账金额:$"+totalDebits+"/n"+
"最终存款:$"+account.getBalance()+"/n"+
"应为 :$"+(initialBalance+totalCredits-totalDebits));
}
/**
* 使用synchronized进行账号的事务操作
*/
public static void operationWithSynchronized(){
int initialBalance=500;
int totalCredits=0;
int totalDebits=0;
int transactionCount=20;
BankWithSync theBank=new BankWithSync();
ClerkWithSync clerk1=new ClerkWithSync(theBank);
ClerkWithSync clerk2=new ClerkWithSync(theBank);
Account account=new Account(1,initialBalance);
Thread clerk1Thread=new Thread(clerk1);
Thread clerk2Thread=new Thread(clerk2);
clerk1Thread.setDaemon(true);
clerk2Thread.setDaemon(true);
clerk1Thread.start();
clerk2Thread.start();
Random rand=new Random();
Transaction transaction;
int amount=0;
//职员1和职员2共进行20次事务操作
for(int i=1;i<=transactionCount;i++){
//职员1入账amount元
transaction=new Transaction(account,Transaction.CREDIT,amount);
totalCredits+=amount;
while(clerk1.isBusy()){
try{
Thread.sleep(25);
}
catch(InterruptedException e){
System.out.println(e);
}
}
clerk1.doTransaction(transaction);
//职员2出账amount元
amount=30+rand.nextInt(31);
transaction=new Transaction(account,Transaction.DEBIT,amount);
totalDebits+=amount;
while(clerk2.isBusy()){
try{
Thread.sleep(25);
}
catch(InterruptedException e){
System.out.println(e);
}
}
clerk2.doTransaction(transaction);
}
//等待两职员工作结束
while(clerk1.isBusy()||clerk2.isBusy()){
try{
Thread.sleep(25);
}
catch(InterruptedException e){
System.out.println(e);
}
}
//打印结果
System.out.println(
"初始存款:$"+initialBalance+"/n"+
"入账金额:$"+totalCredits+"/n"+
"出账金额:$"+totalDebits+"/n"+
"最终存款:$"+account.getBalance()+"/n"+
"应为 :$"+(initialBalance+totalCredits-totalDebits));
}
public static void main(String[] argv){
operationWithUnuseLock();
operationWithReentrantLock();
operationWithSynchronized();
}
}
该博客以两个银行职员同时操作同一账号为例,展示多线程竞争问题。分别用不加控制、ReentrantLock、synchronized三种方式实现,并比较结果。给出了各方式下使用的类,还展示了运行结果及各方式花费时间,同时附上了完整源代码。
1015

被折叠的 条评论
为什么被折叠?



