zoukankan      html  css  js  c++  java
  • Lock

    1.ReentrantLock类

    1.使用ReentrantLock类也可以实现使用synchroized的互斥效果,并且使用起来有很多地方更灵活。

    用法如下

    class MyService{
    //建立锁对象
      private Lock lock=new ReentrantLock();
      public void num(){
      //加锁
          lock.lock();
        for(int i=0;i<10;i++){
         System.out.println(i):
       }
    // 释放锁
       lock.unlock();
       }
    
    
    }

    使用ReentrantLock在基本的功能上和synchroized一样,调用lock.lock(),就像获得了一个“对象监视器”,直到它lock.unlock()以后,其他线程才能获得执行权。

    2.那么使用lock以后,怎么进行线程间通信呢?

    关键字synchronized与wait()和notify()/notifyall()搭配使用可以实现等待/通知。

    使用ReentrantLock也可以实现,但必须借助Condition。一个lock可以创建多个Condition对象。Condition下面有await和signal和signalAl方法与wait()和notify()/notifyall(),怎么用呢?

    class MyService{
    //建立锁对象
      private Lock lock=new ReentrantLock();
    //创建Condition对象.
      private Condition c=lock.newCondition();
      public void awaitOne(){
      //加锁
          lock.lock();
         System.out.println(A):
         c.await();
          System.out.println(B):
    // 释放锁
       lock.unlock();
       }
      public void signalOne(){
      //加锁
          lock.lock();
         c.signal();
    // 释放锁
       lock.unlock();
       }
    
    
    }

    需要注意:一定要在lock.lock()之后才可以await(),因为要首先获得监视器对象。等待通知必须建立在同步的基础上,如果不同步,就会存在竞态条件,就没有存在的意义了。

    上面说了,一个lock可以建多个Condition对象

    class MyService{
    //建立锁对象
      private Lock lock=new ReentrantLock();
    //创建Condition对象.
      private Condition A=lock.newCondition();
      private Condition B=lock.newCondition();
      private Condition C=lock.newCondition();
      public void awaitOne(){
      //加锁
          lock.lock();
         System.out.println(A):
         A.await();
          System.out.println(B):
    // 释放锁
       lock.unlock();
       }
      public void signalOne(){
      //加锁
          lock.lock();
         A.signal();
    // 释放锁
       lock.unlock();
       }
     public void awaitTwo(){
      //加锁
          lock.lock();
         System.out.println(A):
        B.await();
          System.out.println(B):
    // 释放锁
       lock.unlock();
       }
      public void signalTwo(){
      //加锁
          lock.lock();
         B.signal();
    // 释放锁
       lock.unlock();
       }
     public void awaitThree(){
      //加锁
          lock.lock();
         System.out.println(A):
         C.await();
          System.out.println(B):
    // 释放锁
       lock.unlock();
       }
      public void signalThree(){
      //加锁
          lock.lock();
         C.signal();
    // 释放锁
       lock.unlock();
       }
    
    }

    仔细看看这个程序,有什么好处?

    看明白吓了一跳,可以随意指定唤醒的对象了!这是synchroized做不到的,使用synchroized的时候相当于,创建了一个Condition对象,所以唤醒的时候是随机唤醒一个等待的线程。

    用lock怎么实现生产者消费者模式呢?

    class MyService{
      private Lock lock=new ReentrantLock();
      private Condition c=lock.newCondition();
      private boolean isGet=false;
      public void set(){
      lock.lock();
        while(isGet==true){
              c.await();
       
       }
       System.out.pritln("*");
       isGet=true;
       c.signalAll();
      }
    
     public void get(){
      lock.lock();
        while(isGet==false){
              c.await();
       
       }
       System.out.pritln("&");
       isGet=false;
       c.signalAll();
      }
    
    }

    3.公平锁与非公平锁

      锁lock分为公平锁与非公平锁:公平锁获取锁的顺序是按照线程加锁的顺序来分配。非公平锁是一种获取锁的枪战机制,是随机获得锁的,先来的不一定先得到锁,这个方式可能会导致一些弱的线程一直抢不到锁,所以也就是不公平的了。

    Lock lock=new ReentrantLock(boolean isFair);

    通过这个设置是否是公平锁

    公平锁运行起来如下图所示

    可以看到先运行的先获得了锁。非公平锁呢?

     

    先运行的不一定先获得锁。

    4.介绍一下lock类的方法

    getHoldCount()查询当前线程保持此锁定的个数,也就是调用lock()方法的次数!

    getQueueLength() 返回正等待获取此锁定的线程数,也就是说有五个线程,一个获得了锁,剩下四个等。

    getWaitQueueLength() 返回等待与此锁定相关的给定条件Condition的线程估计数,比如说5个线程,每个线程都执行了同一个Condition对象的await()方法,那就会返回5。

    hasQueuedThread(Thread thread)  查询thread线程是否在等待获取锁

    hasQueuedThreads 查询是否有线程正在等待获取锁

    hasWaiters(Condition condition) 查询是否有线程正在等待与此锁定有关的condition条件。也就是查询有没有等待conditon对象的await()。

    ifFair() 判断是不是公平锁

    isHelpBycurrentThread() 查询当前线程是否保持此锁定

    isLocked()查询此锁定是否由任意线程保持

    lockInterruptibly() 如果当前线程未被中断,则获取锁,如果被锁定了,则抛出异常。

    tryLock()仅在调用时锁定未被另一个线程保持时才获取该锁定。

    tryLock(long timeout,TimeUnit unit)如果锁定在给定的时间内没有被其他的线程保持,且当前线程未被中断,则获取该线程。

    awaitUninterruptibly() 使用这个代替await()可以在线程被interrput()的时候不抛出异常只停止运行

    5.使用Condtion实现顺序执行

    class Mysevice{
     private static int isNum=1;
      private Lock lock=new ReentrantLock();
      private Condition A=lock.newCondtion();
      private Condition B=lock.newCondtion();
      private Condition C=lock.newCondtion();
    public static void main(String[] args){
         Thread t1=new Thread(){
         public void run(){
              while(isNum!=1){
                A.await();
    
             }
          for(int i=0;i<3;i++){
            System.out.println(Thread.currentend.getName()+i);
          }
           isNum=2;
          B.singalAll();
    
         }
    
         };
    Thread t2=new Thread(){
         public void run(){
              while(isNum!=2){
                B.await();
    
             }
          for(int i=0;i<3;i++){
            System.out.println(Thread.currentend.getName()+i);
          }
           isNum=3;
          C.singalAll();
    
         }
    
         };
    Thread t3=new Thread(){
         public void run(){
              while(isNum!=3){
                A.await();
    
             }
          for(int i=0;i<3;i++){
            System.out.println(Thread.currentend.getName()+i);
          }
           isNum=1;
          A.singalAll();
    
         }
    
         };
    
    
    }
      
    }

    这就是使用Condition的好处,可以随机也可以按顺序来,synchroized是做不到的。

    2.ReentrantReadWriteLock类

    1.为什么要使用这个类呢?

    因为ReentrantLock具有完全排他的效果,即同一时间只有一个在执行lock.lock()方法后面的任务,这样做虽然保证了安全,但是在一些不需要操作实例变量的场景下,这样效率就很低。所以使用读写锁。读写锁有什么优点呢?

    class A{
    private Lock lock=new ReentrantReadWriteLock();
    public void read(){
    //使用读锁
       lock.readLock().lock();
    //释放读锁
      lock.readLock().unlock();
    }
    public void write(){
    //使用写锁
       lock.writeLock().lock();
    //释放写锁
      lock.writeLock().unlock();
    }
    
    }

    读锁与读锁异步,读锁与写锁同步,写锁与写锁同步。写锁与读锁同步。也就是说,不会修改实例变量的情况下读锁与读锁异步,只提供了可见性

  • 相关阅读:
    map按照值排序
    结构体的三种排序方式
    归并排序
    数组模拟双向链表
    二刷斐波那契高精度
    2019年9月训练(贰)区间DP (luogu 4290)
    2019年9月训练(壹)数位DP (HDU 2089)
    2019年8月训练(贰)
    2019年8月训练(壹)二分,三分
    2019年7月训练(柒)
  • 原文地址:https://www.cnblogs.com/wxw7blog/p/7396897.html
Copyright © 2011-2022 走看看