ReentrantLock -入门

ReentrantLock 是什么

  重入锁,是一个可以在持有相同锁的执行代码之间进行互斥的锁。具有与使用synchronized 方法和语句时同样的基本行为和语义,但是功能更多,也更加灵活。一个ReentrantLock 由一个线程调用lock方法获取,如果锁没有被另外一个线程锁定。当前线程成功将锁获取并锁定,且没有解锁,那么方法将返回true。如果当前线程已经获取到该锁,调用lock方法,将立即返回true。

ReentrantLock 跟synchronized 区别

  两者都是阻塞式同步锁,当一个线程占用锁后,其他线程无法进入被锁定的代码块。区别是:ReentrantLock 在使用的时候,必须创建lock对象。必须在开始部分写lock语句,结束部分写unlock语句。如果没有手工释放,会导致死锁。同样,ReentrantLock的锁粒度要比synchronized要细,也更加灵活。

ReentrantLock  基本方法

  lock-unLock,基本的加锁解锁实现,如果锁没有被另外一个线程占用则立即返回true,如果当前线程本身已经持有该锁定,则保持计数增加1,返回true。如果锁被其他线程保持,则当前线程阻塞,在获取到 锁之前一直处于休眠状态。代码如下:

 1     Lock lock = new ReentrantLock();
 2     
 3     void m1() {
 4         try  {
 5             lock.lock();
 6             for (int i = 0; i < 10; i++) {
 7                 TimeUnit.SECONDS.sleep(1);
 8                 System.out.println(i);
 9             }
10         } catch (Exception e) {
11             e.printStackTrace();
12         }finally {
13             lock.unlock();
14         }
15     }
16     
17     void m2() {
18         try {
19             lock.lock();
20             System.out.println("m2.....");
21         } catch (Exception e) {
22             e.printStackTrace();
23         }finally {
24             lock.unlock();
25         }
26     }
27     
28     public static void main(String[] args) {
29         T02_ReentrantLock2 rl = new T02_ReentrantLock2();
30         new Thread(rl::m1).start();
31         try {
32             TimeUnit.SECONDS.sleep(1);
33         } catch (Exception e) {
34             e.printStackTrace();
35         }
36         new Thread(rl::m2).start();
37     }
38     

  trylock,当lock方法执行的时候,如果获取不到锁,线程就会阻塞。trylock方法可以在不阻塞线程的情况下,尝试获取锁。如果没有被其他线程保持锁定,那么当前线程获取锁定,并返回true。如果锁由另一个线程持有,则该方法将立即返回值为false 。trylock方法还有一个多态的方法,可以传入一个超时时间,在超时结束之前未获取到锁,将会等待。超时结束仍然未获取到锁,将会返回false。代码如下:

 1     Lock lock = new ReentrantLock();
 2 
 3     void m1() {
 4         try {
 5             lock.lock();
 6             for (int i = 0; i < 10; i++) {
 7                 TimeUnit.SECONDS.sleep(1);
 8                 System.out.println(i);
 9             }
10         } catch (Exception e) {
11             e.printStackTrace();
12         } finally {
13             lock.unlock();
14         }
15     }
16 
17     /**
18      * 可以使用trylock对代码进行尝试锁定,不管锁定与否,方法都将继续执行,
19      * 可以根据tryLock的返回值来确定锁定,也可以指定tryLock的时间,超时后抛出异常,
20      */
21     void m2() {
22         /*
23          * boolean locked = lock.tryLock();
24          * System.out.println("m2....."+locked);
25          * if(locked) locked.unlock();
26          */
27         boolean locked = false;
28         
29         try {
30             locked = lock.tryLock(5,TimeUnit.SECONDS);
31             
32             System.out.println("m2....."+locked);
33         } catch (Exception e) {
34             e.printStackTrace();
35         } finally {
36             if(locked)lock.unlock();
37         }
38     }
39 
40     public static void main(String[] args) {
41         T02_ReentrantLock3 rl = new T02_ReentrantLock3();
42         new Thread(rl::m1).start();
43         try {
44             TimeUnit.SECONDS.sleep(1);
45         } catch (Exception e) {
46             e.printStackTrace();
47         }
48         new Thread(rl::m2).start();
49     }

  lockInterruptibly

    public static void main(String[] args) {
        Lock lock = new ReentrantLock();
        Thread t1 = new Thread(() -> {
            lock.lock();
            try {
                System.out.println("t1开始执行");
                TimeUnit.SECONDS.sleep(Integer.MAX_VALUE);
                System.out.println("t1执行结束");
            } catch (InterruptedException e) {
                System.out.println("interruped");
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        });
        t1.start();
        Thread t2 = new Thread(() -> {
            System.out.println("t2 开始执行");
            boolean isLock =false;
            try {
                try {
                    lock.lockInterruptibly(); // 可以对interrup()方法做出响应
                    isLock = true;
                } catch (Exception e) {
                    e.printStackTrace();
                    isLock = false;
                }
                System.out.println("t2 获取锁");
                try {
                    TimeUnit.SECONDS.sleep(5);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("t2 end");
            
            } finally {
                if (isLock) {
                    lock.unlock();
                }
            }
        });
        t2.start();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (Exception e3) {
            e3.printStackTrace();
        }

        t2.interrupt();// 打断线程2的等待

    }

  公平锁

  公平锁,在线程获取锁的时候,执行一定的公平策略。线程先申请锁,就会先获取锁,但是不能保证线程在执行的时候也是公平的。代码如下:

 1     private static ReentrantLock lock = new ReentrantLock(true);// 参数为true的时候,表示为公平锁,等在前面的先执行
 2 
 3     @Override
 4     public void run() {
 5         for (int i = 0; i < 100; i++) {
 6             lock.lock();
 7             try {
 8                 System.out.println(Thread.currentThread().getName() + "执行了");
 9             }  finally {
10                 lock.unlock();
11             }
12         }
13     }
14 
15     public static void main(String[] args) {
16         T02_ReentrantLock5 rl = new T02_ReentrantLock5();
17         Thread t1 = new Thread(rl);
18         Thread t2 = new Thread(rl);
19         t1.start();
20         t2.start();
21 
22     }

  分组唤醒

  synchronized在线程wait时,如果唤醒,需要将所有当前锁下的线程全部唤醒,而ReentrantLock提供了一个分组唤醒的功能。通过 newCondition方法创建一个分组,然后通过分组.await()方法进行分组等待。通过分组.signalAll() 方法进行分组唤醒。现在用一个生产者消费者的案例进行说明:

 1 {
 2     final private   LinkedList<T> lists = new LinkedList<>();
 3     final  private int MAX = 10;
 4     private volatile int count = 0;
 5     private Lock lock = new ReentrantLock();
 6     // 生产者
 7     private Condition producer = lock.newCondition();
 8     // 消费者
 9     private Condition conSumer = lock.newCondition();
10 
11     public void put(T t){
12         try {
13             lock.lock();
14             while (count==MAX){
15                 System.out.println("队列已满,生产者等待");
16                 producer.await();
17                 System.out.println("生产者被唤醒");
18             }
19             lists.add(t);
20             ++count;
21             System.out.println("加入对象,当前队列数量为"+count);
22             conSumer.signalAll();
23         } catch (InterruptedException e) {
24             e.printStackTrace();
25         }finally {
26             lock.unlock();
27         }
28 
29     }
30     public  T get(){
31         T t= null;
32         try {
33             lock.lock();
34             while (count == 0) {
35                 System.out.println("消费者等待");
36                 conSumer.await();
37                 System.out.println("消费者被唤醒");
38             }
39             t= lists.getFirst();
40             --count;
41             System.out.println("消费,当前队列数量为"+count);
42             System.out.println("消费者执行");
43             producer.signalAll();
44 
45             } catch (InterruptedException e) {
46                 e.printStackTrace();
47             }finally {
48                 lock.unlock();
49             }
50 
51         return t;
52     }
53 
54     public static void main(String[] args) {
55         MyContainer1 qu= new MyContainer1();
56         for (int i = 0; i < 10; i++) {
57         new Thread(()->{
58            while (true){
59                 qu.put(new Object());
60             }
61             }).start();
62         }
63         for (int i = 0; i < 30; i++) {
64             new Thread(() -> {
65                 while (true){
66                     qu.get();
67                 }
68             }).start();
69         }
70     }
71 
72 
73 }

原文地址:https://www.cnblogs.com/liyasong/p/ReentrantLock.html