Java核心技术学习---多线程,锁,同步,条件对象部分应用源码

时间:2021-09-14 13:05:11

Bank.java

package testcase;

import java.util.*;
import java.util.concurrent.locks.*;

//考虑同步的多线程编程
public class Bank
{
private final double[] accounts;
private Lock bankLock;
private Condition sufficientFunds;


public Bank(int n,double initialBalance)
{
accounts = new double[n];
Arrays.fill(accounts,initialBalance);
bankLock = new ReentrantLock(); //构建一个可被用来保护临界区的可重入锁
sufficientFunds = bankLock.newCondition(); //获得条件对象,一个锁可以有多个条件对象

}

public void transfer(int from,int to,double amount) throws InterruptedException
{ //用ReentrantLock保护代码块
bankLock.lock(); //一个ReentrantLock对象 锁对象
try
{
//若满足以下条件(余额不足),则阻塞当前线程,放弃锁,
//这样使其他线程可以进行增加余额的操作。
while(accounts[from] < amount)
{
sufficientFunds.await(); //当前线程被阻塞
}
System.out.println(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());
//当另一个线程调用同一条件的signalAll方法时,锁可用且处于阻塞状态的线程才能解除阻塞。
sufficientFunds.signalAll();//该调用重新激活因为该条件而等待的所有线程
//signalAll();不会立即激活一个等待线程,仅仅解除等待线程的阻塞,以便这些线程可以在
//当前线程退出同步方法后,通过竞争实现对对象的访问。
}
finally
{
//解锁操作放在finally子句之内至关重要。若临界区代码抛出异常,锁必须被释放,
//否在其他线程将永远阻塞
bankLock.unlock(); //解锁操作
}
}

public double getTotalBalance()
{
bankLock.lock();
try
{
double sum = 0;
for(double a :accounts)
{
sum += a;
}
return sum;
}
finally
{
bankLock.unlock();
}
}

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



}

SynBankTest.java

package testcase;

public class SynBankTest {
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 = 0;
Runnable r = ()->{
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(); //开启线程
}
}

}