Java高并发--可重入锁(ReentrantLock)

154 阅读1分钟

重入锁ReentrantLock

重入锁能代替关键字synchronized进行使用,在jdk1.6以后,synchronized与重入锁的性能差距并不大。它与关键字synchronized相比,重入锁有着显示的操作过程,我们必须手动指定何时加锁,何时释放锁。也是因为这样,重入锁对逻辑控制的灵活性就远远优于关键字synchronized,但我们需要注意在退出临界区时,必须记得释放锁,否则其他线程就没有机会再访问临界区了。

简单使用代码:

import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockTest implements Runnable{
    public static ReentrantLock lock=new ReentrantLock();
    public static int i=0;
    @Override
    public void run(){
        for (int j=0;j<1000000;j++){
            lock.lock();
            try{
                i++;
            }finally {
                lock.unlock();
            }
        }
    }

    public static void main(String[] args) {
        ReentrantLockTest t=new ReentrantLockTest();
        Thread t1=new Thread(t);
        Thread t2=new Thread(t);
        t1.start();
        t2.start();
        try {
            t1.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        try {
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(i);
    }
}

运行结果:

image.png

为什么该锁叫做重入锁呢?是因为这种锁是可以反复进入的,一个线程可以连续多次获得同一把锁。但我们也需要注意,如果同一个线程多次获得锁,那么在释放锁的时候,也必须释放相同次数。

  • 释放次数多了,就会得到一个ILLegalMonitorStateException异常;
  • 释放次数少了,那么就相当于线程还持有这个锁,会占用资源,其他线程也无法进入临界区。

ReentrantLock几个重要方法如下:

  • lock():获得锁,如果锁已经被占用,则等待;
  • lockInterruptibly():获得锁,但优先响应中断;
  • tryLock():尝试获得锁,如果成功,则返回true,失败返回false。该方法不等待,立即返回;
  • tryLock(Long time,TimeUnit unit):在给定的时间内获得锁;
  • unlock():释放锁。