-
ReentrantLock是唯一实现了Lock接口的类,并且提供了更多的方法
-
使用这个类的时候,切记手动释放锁
-
锁必须声明为一个全局变量,因为每个线程的方法都会把变量保存为一个本地的副本,如果在业务处理中声明了锁的变量,那么不同的线程获取的是不同的锁,是没有办法起到互斥的作用的,所以需要锁对象声明为全局变量,如下图所示:
public class LockTest{
public static void main (String[] args){
private List list = new ArrayList();
final LockTest lockTest = new LockTest();new Thread(){ public void run(){ lockTest.insert(Thread.currentThread()); } }.start(); new Thread(){ public void run(){ lockTest.insert(Thread.currentThread()); } }.start();
}
public void insert(Thread thread){
Lock lock = new ReentrantLock();//此处线程会拷贝副本
lock.lock();//加锁
try{
System.out.println(thread.getName()+“得到了锁”);
//业务操作}catch(Exception e){ // }finally{ System.out.println(thread.getName()+"释放了锁"); lock.unLock();//手动释放锁 }
}
}
注意:这段代码的输出结果可能会让人意向不到,毕竟我们已经在业务操作上进行了加锁。但是现实的输出结果是:
Thread-0得到了锁
Thread-1得到了锁
Thread-1释放了锁
Thread-0释放了锁
为啥呢?
第二个线程之所以在第一个线程还没有释放锁之前就获得了锁,是因为在这个insert方法中,lock变量是一个局部的变量,每一个线程执行到这个方法的时候,都会将这个变量保存一个副本。
所以我们的加锁的操作获得的是不同的锁,所以线程之间没有进行互斥。
所以,只需要将lock声明为全局变量即可。
2.使用tryLock()获取锁的操作
2.1将lock申明为全局变量
2.2在insert()方法中加入判断:
if(lock.tryLock()){
try{
//上面的代码
}catch(Exception e){
//上面的代码
}finally{
lock.unLock();
}
}
注意这个代码的输出结果为:
Thread-0获得了锁
Thread-1获取锁失败
Thread-0释放了锁。
如此,是正确的输出结果