• 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 }

  • 相关阅读:
    动态控件、控件的生存周期和ViewState的运行细节
    PDA开发初级经验
    编译原理知识总结
    A System for Collecting and Analyzing TopicSpecific Web Information
    show tooltip on control
    慧科新闻、慧科搜索
    内存泄漏
    www.sinobankers.com/forum“今日新帖”“最新会员”“论坛热贴”消失问题
    一堆信息抽取的资料文档
    showing tooltip on controls (description on TTN_NEEDTEXT)
  • 原文地址:https://www.cnblogs.com/liyasong/p/ReentrantLock.html
Copyright © 2020-2023  润新知