从java SE 5.0开始,有两种机制防止代码块收到并发访问的干扰。
一:synchronized关键字:自动提供一个锁以及相关的“条件”。
二:ReentrantLock类。
用ReentrantLock类保护代码块的基本机构如下:
myLock.lock(); try{ //原子操作部分 }finally{ myLock.unlock(); }
这个结构确保任何时刻只有一个线程进入临界区。一旦一个线程封锁了锁对象,其他任何线程调用lock时,他们会被阻塞,直到第一个线程释放锁对象。
在前一个例子中我们只要保证在银行转账时操作的原子性就能保证银行资金总和的不变性。所以只需将transfer()方法加锁对象。
public class Bank { public Bank(int n,double initialBalance){ accounts = new double[n]; for(int i=0;i<n;i++){ accounts[i] = initialBalance; } } public void transfer(int from,int to,double amount){ bankLock.lock(); try{ if(accounts[from] < amount) return; System.out.println(); accounts[from] -= amount; System.out.println("当前线程为"+Thread.currentThread()+"----账户"+from+"转移"+amount+"到账户"+to); accounts[from] += amount; System.out.println("当前线程为"+Thread.currentThread()+"----账户"+to+"接收账户"+from+"转移的资金"+amount); System.out.println("当前线程为"+Thread.currentThread()+"----资金总额为"+getTotalBalance()); }finally { bankLock.unlock(); } } public double getTotalBalance(){ double sum = 0d; for(double a : accounts){ sum += a; } return sum; } public int size(){ return accounts.length; } private final double[] accounts; private Lock bankLock = new ReentrantLock(); }
摘录部分日志内容:
当前线程为Thread[Thread-43,5,main]----账户43转移660.0024662254845到账户6 当前线程为Thread[Thread-43,5,main]----账户6接收账户43转移的资金660.0024662254845 当前线程为Thread[Thread-43,5,main]----资金总额为100000.0 当前线程为Thread[Thread-19,5,main]----账户19转移692.2118024486375到账户29 当前线程为Thread[Thread-19,5,main]----账户29接收账户19转移的资金692.2118024486375 当前线程为Thread[Thread-19,5,main]----资金总额为100000.0 当前线程为Thread[Thread-99,5,main]----账户99转移267.27288053231626到账户27 当前线程为Thread[Thread-99,5,main]----账户27接收账户99转移的资金267.27288053231626 当前线程为Thread[Thread-99,5,main]----资金总额为100000.0 当前线程为Thread[Thread-31,5,main]----账户31转移149.00126699919258到账户51 当前线程为Thread[Thread-31,5,main]----账户51接收账户31转移的资金149.00126699919258 当前线程为Thread[Thread-31,5,main]----资金总额为100000.0 当前线程为Thread[Thread-75,5,main]----账户75转移618.0609778584749到账户54 当前线程为Thread[Thread-75,5,main]----账户54接收账户75转移的资金618.0609778584749 当前线程为Thread[Thread-75,5,main]----资金总额为100000.0 当前线程为Thread[Thread-55,5,main]----账户55转移208.92087295440354到账户3 当前线程为Thread[Thread-55,5,main]----账户3接收账户55转移的资金208.92087295440354 当前线程为Thread[Thread-55,5,main]----资金总额为100000.0 当前线程为Thread[Thread-39,5,main]----账户39转移78.93128043916242到账户41 当前线程为Thread[Thread-39,5,main]----账户41接收账户39转移的资金78.93128043916242 当前线程为Thread[Thread-39,5,main]----资金总额为100000.0