问题
在《一个简单的办法保证Java并行计算的原子性》中,我们使用一个boolean型变量保证了原子性的操作。但是这个类在使用的时候,还是有点麻烦,主要的原因是需要主动去检测运行状态。
解决
基于同样的思想,为了简化这个操作,Java专门提供了一个类ReentrantLock,具体用法如下:
1 定义一个全局的 ReentrantLock 对象
ReentrantLock lock = new ReentrantLock();
2 在需要用到的地方使用它
lock.lock();
// 需要原子化的代码块
lock.unlock();
在这个线程在使用时会更方便,因为在同步时,我们不需要再使用while循环来进行检测,因为这个锁是线程阻塞的,即如果另一个线程需要在当前线程进行原子操作时进行访问,则自动会进入等待。等主线程完成任务后,另一线程才会进入。
银行示例
还是以前文的银行示例,代码可以这么实现:
class ThreadDemo extends Thread throws Exception{
// 1. 定义一个全局 ReentrantLock 对象
ReentrantLock lock = new ReentrantLock();
// 取款为一个耗时的操作,代码略
public void withdraw(String accountName, double money){
}
// 存款同样为一个耗时的操作,代码略
public void deposit(String accountName, double money){
}
// 2. 在需要原子化的代码块前后使用
@Override
public void run(){
lock.lock();
withdraw("bankAccount1", 100); // 从帐户1取100
deposit("bankAccount2", 100); // 向帐户2存100
lock.unlock();
}
public static void main(String[] args){
ThreadDemo td = new ThreadDemo();
td.start();
// 之前的等待代码不再需要,可在本线程中直接进行调用
// 当 td.withdrow() 方法已经在调用中,则本线程自动进入等待状态完成才会进入。
td.withdraw(200);
}
}
小结
通过以上的示例可以看出,使用 ReentrantLock 相比之下会更加方便,不需要编写等待代码,同时它也是线程安全的。建议在多线程操作中,优先考虑使用此类。