Java并发包之Lock接口的实现类ReentrantLock

299 阅读1分钟

ReentrantLock称之为可重入锁

  • 是Lock的实现类,其中方法的功能已经介绍过了,不在赘述。

先上代码尝尝鲜

常规版

public class LockT {
    private final Lock lock = new ReentrantLock(); //可重入锁
    public void f1(){
        try {
            lock.lock();
            System.out.println("正在执行f1");
        }finally {
            lock.unlock();
        }
    }
    public void f2(){
        try {
            lock.lock();
            System.out.println("正在执行f2");
        }finally {
            lock.unlock();
        }
    }
    public static void main(String[] args) {
        LockT T = new LockT();
        new Thread(()-> {//该线程会执行f1()
            for (int i = 0;i<10;i++){
                T.f1();
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
        new Thread(()-> {//该线程会执行f2()
            for (int i = 0;i<10;i++){
                T.f2();
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}
  • 结果:

image.png

如果把f1()lock.unlock();注释掉,会如何?

  • 代码小改一丢丢
public class LockT {
    private final Lock lock = new ReentrantLock(); //可重入锁
    public void f1(){
        try {
            lock.lock();
            System.out.println("正在执行f1");
        }finally {
            //lock.unlock();    //改了这
        }
    }
    public void f2(){
        try {
            lock.lock();
            System.out.println("正在执行f2");
        }finally {
            lock.unlock();
        }
    }
    public static void main(String[] args) {
        LockT T = new LockT();
        new Thread(()-> {//该线程会执行f1()
            for (int i = 0;i<10;i++){
                T.f1();
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
        new Thread(()-> {//该线程会执行f2()
            for (int i = 0;i<10;i++){
                T.f2();
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}
  • 结果:

image.png

  • 原因:
    • 首先,f1()没有释放锁(unlock),这就导致执行f2()的线程无法执行也就无法结束该程序 其次,这是可重入锁,这就导致执行f1()的线程在没有释放锁的情况下还可以再次获取锁,只能是没有释放锁的线程可以再次获取。

如果不想让线程永久阻塞可以试试tryLock()

public class LockT {
    private final Lock lock = new ReentrantLock(); //可重入锁
    public void f1(){
        try {
            lock.lock();
            System.out.println("正在执行f1");
        }finally {
            //lock.unlock();
        }
    }
    public void f2(){
        boolean res = false ;
        try {
            res = lock.tryLock(1, TimeUnit.SECONDS);//在一分钟内没有获取到锁就执行else
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if(res){
            try {
                System.out.println("f2获取到了锁");
            } finally {
                lock.unlock();
            }
        }
        else{
            System.out.println("f2没有获取到锁");
        }
    }
    public static void main(String[] args) {
        LockT T = new LockT();
        new Thread(()-> {//该线程会执行f1()
            for (int i = 0;i<10;i++){
                T.f1();
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
        new Thread(()-> {//该线程会执行f2()
            for (int i = 0;i<10;i++){
                T.f2();
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}
  • 结果 image.png

在有正常释放锁的情况下试试tryLock()

  • 顺便把main方法代中是sleep移到f()方法中
public class LockT {
    private final Lock lock = new ReentrantLock(); //可重入锁
    public void f1(){
        try {
            lock.lock();
            System.out.println("正在执行f1");
            Thread.sleep(1000);
        }catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
    public void f2(){
        boolean res = false ;
        try {
            res = lock.tryLock(1, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if(res){
            try {
                System.out.println("f2获取到了锁");
            } finally {
                lock.unlock();
            }
        }
        else{
            System.out.println("f2没有获取到锁");
        }
    }
    public static void main(String[] args) {
        LockT T = new LockT();
        new Thread(()-> {//该线程会执行f1()
            for (int i = 0;i<10;i++){
                T.f1();
            }
        }).start();
        new Thread(()-> {//该线程会执行f2()
            for (int i = 0;i<10;i++){
                T.f2();
            }
        }).start();
    }
}
  • 结果:

image.png

小结

  • 本篇只介绍了ReentrantLock常规的一些方法,还有一些其他方法lockInterruptibly()和另外有关该类的构造方法ReentrantLock(boolean fair) ,有缘再介绍