问题

在《一个简单的办法保证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 相比之下会更加方便,不需要编写等待代码,同时它也是线程安全的。建议在多线程操作中,优先考虑使用此类。