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();
}

}

 

 

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

 

posted @ 2017-08-19 16:03  竹马今安在  阅读(229)  评论(0编辑  收藏  举报