JDK并发包[同步控制]

Posted yuanjiehe

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JDK并发包[同步控制]相关的知识,希望对你有一定的参考价值。

重入锁ReentrantLock[Re-entrant Lock]

  1. ReentrantLock与Synchronized区别:

    1. 重入锁可以反复进入

      lock.lock();
      lock.lock();
      try{
      	i++;
      }finally{
      	lock.unlock();
      	lock.unlock();
      }
      
          //RentrantLock.java JDK8
      	/**
           * Acquires the lock.
           *
           * <p>Acquires the lock if it is not held by another thread and returns
           * immediately, setting the lock hold count to one.
           *
           * <p>If the current thread already holds the lock then the hold
           * count is incremented by one and the method returns immediately.
           *
           * <p>If the lock is held by another thread then the
           * current thread becomes disabled for thread scheduling
           * purposes and lies dormant until the lock has been acquired,
           * at which time the lock hold count is set to one.
           */
          public void lock() {
              sync.lock();
          }
      
          /**
           * Attempts to release this lock.
           *
           * <p>If the current thread is the holder of this lock then the hold
           * count is decremented.  If the hold count is now zero then the lock
           * is released.  If the current thread is not the holder of this
           * lock then {@link IllegalMonitorStateException} is thrown.
           *
           * @throws IllegalMonitorStateException if the current thread does not
           *         hold this lock
           */
          public void unlock() {
              sync.release(1);
          }
      
    2. 如果同一个线程多次获得锁,那么在释放锁的时候,也需要释放相同次数

    3. 若释放锁的次数过多,将会得到 java.lang.IllegalMonitorStateException异常

  2. 高级功能

    1. 中断响应[lockInterruptibly()]:

      如果一个线程在等待锁,那么它依然可以收到一个通知,被告知无需再等待,可以停止工作了。

      public class IntLock implements Runnable {
          public static ReentrantLock lock1 = new ReentrantLock();
          public static ReentrantLock lock2 = new ReentrantLock();
          int lock;
      
          public IntLock(int lock) {
              this.lock = lock;
          }
      
          @Override
          public void run() {
              try {
                  if (lock == 1) {
                      lock1.lockInterruptibly();
                      try {
                          Thread.sleep(500);
                      } catch (InterruptedException e) {
                      }
                      lock2.lockInterruptibly();
                  } else {
                      lock2.lockInterruptibly();
                      try {
                          Thread.sleep(500);
                      } catch (InterruptedException e) {
                      }
                      lock1.lockInterruptibly();
                  }
              } catch (InterruptedException e) {
                  e.printStackTrace();
              } finally {
                  if (lock1.isHeldByCurrentThread()) {
                      lock1.unlock();
                  }
                  if (lock2.isHeldByCurrentThread()) {
                      lock2.unlock();
                  }
                  System.out.println(Thread.currentThread().getId() + ":线程退出");
              }
          }
      
          public static void main(String[] args) throws InterruptedException {
              IntLock r1 = new IntLock(1);
              IntLock r2 = new IntLock(2);
              Thread t1 = new Thread(r1);
              Thread t2 = new Thread(r2);
              t1.start();
              t2.start();
              Thread.sleep(1000);
              t2.interrupt();
          }
      }
      
    2. 锁申请等待限时[tryLock()]:

      public class TimeLock implements Runnable{
          public static ReentrantLock lock = new ReentrantLock();
          @Override
          public void run(){
              try{
                  if(lock.tryLock(5, TimeUnit.SECONDS)){
                      Thread.sleep(6000);
                  }else{
                      System.out.println("get lock failed");
                  }
              }catch (InterruptedException e){
                  e.printStackTrace();
              }finally {
                  if(lock.isHeldByCurrentThread()){
                      lock.unlock();
                  }
              }
          }
      
          public static void main(String[] args) {
              TimeLock tl = new TimeLock();
              Thread t1 = new Thread(tl);
              Thread t2 = new Thread(tl);
              t1.start();
              t2.start();
          }
      }
      
    3. 公平锁[public ReentrantLock(boolean fair)]:

      1. 大多数情况下,锁的申请都是非公平的。系统每次从锁的等待队列中随机挑选一个。
      2. 当ReentrantLock 的fair参数为true时,锁是公平的。
      3. 公平锁需要系统维护一个有序队列,实现成本高,性能相对低下。
  3. 方法总结

    ReentrantLock重要方法 作用
    lock() 获得锁,若锁以及被占用,则等待
    lockInterruptibly() 获得锁,但是优先响应中断
    tryLock() 尝试获得锁
    tryLock(long time, TimeUnit unit) 在time时间内尝试获得锁
    unLock() 释放锁

重入锁的搭档:Condition条件

  1. await() 方法会使当前线程等待,同时释放锁,当其他线程使用signal()或者signalAll()方法时,线程会重新获得锁并重新执行。当线程中断时,也能挑出等待。
  2. awautUninterruptibly() 方法与await() 方法基本相同,但是并不会在等待过程中响应中断。
  3. signal() 方法用于唤醒一个在等待中的线程。
  4. signalAll() 唤醒所有在等待中的线程。

允许多个线程同时访问:Semaphore信号量

  1. 信号量演示例子

    public class SempDemo implements Runnable{
        final Semaphore semp = new Semaphore(5);
        @Override
        public void run(){
            try{
                semp.acquire();
                Thread.sleep(2000);
             	System.out.println(Thread.currentThread().getId()+":done!");
                semp.release();
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
    
        public static void main(String[] args) {
            ExecutorService exec = Executors.newFixedThreadPool(20);
            final SempDemo demo = new SempDemo();
            for(int i=0;i<20;i++){
                exec.submit(demo);
            }
        }
    }
    
  2. 关键方法

    Semaphore方法 方法描述
    acquire() 从此信号量获取许可证,阻塞直到可用
    acquireUninterruptibly() 同acquire(), 但是不响应中断
    release() 释放一个许可证

ReadWriteLock读写锁

  1. 特点:
    • 读-读不互斥;读-读之间不阻塞
    • 读-写互斥;读阻塞写,写阻塞读
    • 写-写互斥;写-写阻塞

倒计时器:CountDownLatch

  1. 作用:允许一个或多个线程等待直到其他线程完成的同步辅助
  2. 使用给定的计数初始化,await方法阻塞,直到由于countDown方法的调用导致当前计数器计数清零,之后所有等待线程被释放

循环栅栏:CyclicBarrier

  1. 作用:允许一组线程全部等待彼此达到共同屏蔽点的同步辅助,可重复使用

线程阻塞工具类:LockSupport

  1. 作用:可以在线程内任意位置让线程阻塞

以上是关于JDK并发包[同步控制]的主要内容,如果未能解决你的问题,请参考以下文章

Java高并发--------JDK并发包-------3

Java高并发--------JDK并发包-------3

JDK并发包

[JCIP笔记]JDK并发包

Java并发包--ReentrantLock

Java并发包--ReentrantLock