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. 作用:可以在线程内任意位置让线程阻塞

原文地址:https://www.cnblogs.com/YuanJieHe/p/12607836.html

时间: 2024-11-02 13:12:54

JDK并发包[同步控制]的相关文章

Java多线程--JDK并发包(2)

Java多线程--JDK并发包(2) 线程池 在使用线程池后,创建线程变成了从线程池里获得空闲线程,关闭线程变成了将线程归坏给线程池. JDK有一套Executor框架,大概包括Executor.ExecutorService.AbstractExeccutorService.ThreadPoolExecutor.Executors等成员,位于java.util.concurrent包下.它们之间的关系如下: Executor是顶层的接口,ExecutorService接口继承了它,Abstrc

JAVA高并发程序设计学习-JDK并发包:同步控制一

JDK内部提供了大量的API和框架,这里主要介绍三部分 多线程同步控制方法 线程池,提高线程调度的性能 JDK的并发容器 重入锁:java.util.concurrent.locks.ReenterLock 在代码中,类ReenterLock实现了Runnable,其中有static的变量i,在run()方法中会对i进行自增操作. 自增操作的步骤为:get-set,先获取值再增加值. 如果在这里不进行控制的话,会导致get的值不是最新set的值. 因此,在自增的时候使用锁进行控制,保证get-s

JDK并发包

1. 各种同步控制工具的使用 1.1 ReentrantLock(重用锁) 1)与synchronized的区别是,它需要手动申请锁与解锁,在 finally 块中释放锁,而synchronized是JVM自动处理的.可控性上ReentrantLock更强. 由于ReentrantLock是重入锁,所以可以反复得到相同的一把锁,它有一个与锁相关的获取计数器,如果拥有锁的某个线程再次得到锁,那么获取计数器就加1,然后锁需要被释放两次才能获得真正释放(重入锁). 注:synchronized 也是可

JDK并发包温故知新系列(五)—— 显式锁与显式条件

显式锁-Lock与ReadWriteLockJDK针对Lock的主要实现是ReentrantLock,ReadWriteLock实现是ReentrantReadWriteLock.本文主要介绍ReentrantLock. ReentrantReadWriteLock两把锁共享一个等待队列,两把锁的状态都由一个原子变量表示,特有的获取锁和释放锁逻辑. ReentrantReadWriteLock的基本原理:读锁的获取,只要求写锁没有被线程持有就可以获取,检查等待队列,逐个唤醒等待读锁线程,遇到等待

jdk并发包ReentrantLock 源码导读

1,ReentrantLock实现了Lock接口,下面是Lock接口.定义了一些Lock的基本操作. 2,ReentrantLock根据在高并发下获取锁的算法分为FairSync和NonfairSync两种.默认为NonfairSync. 3,FairSync和NonfairSync继承了Sync.而Sync是锁的基础控制类.FairSync依然需要检查当前线程是否是等待队列的第一个,NonfairSync则不需要直接从列表中取一个.实际中公平锁吞吐量比非公平锁小很多. 4,Sync通过Abst

jdk并发包 CopyOnWriteArrayList源码分析

CopyOnWriteArrayList是jdk1.5并法包里面用于处理高并发下,读多写少的情况下,降低锁等待的集合类.下面对该类实现做一个简要的分析 1,首先CopyOnWriteArrayList是实现了List接口,对=List接口的相关方法进行了实现. 2,下面的它的add方法,会首先加锁,然后copy原List内部的数组,然后对新数组长度加1后释放锁.由于数组copy速度很快,切在读多写少的情况下锁开销比较少 public boolean add(E e) { final Reentr

安装JDK,配置环境变量

在JDK开发包下载完后,需要对其进行安装,在安装完后才能编译和运行Java程序. JDK 的安装非常简单,我所使用的JDK版本为:jdk-8u45-windows-x64.exe 安装JDK 本人笔记本电脑系统为win7 64位. 双击文件:jdk-8u45-windows-x64.exe 点击下一步后,选择安装目录: 选择好安装目录后,点击下一步,会自定安装 选择JRE的安装目录 更改好安装目录到jdk同级目录下即可,瞬间安装完成,点击关闭即可. 配置JAVA环境变量 在JDK安装完成之后,最

JDK多任务执行框架(Executor框架)

Executor的常用方法 为了更好的控制多线程,JDK提供了一套线程框架Executor,帮助开发人员有效地进行线程控制.它们都在java.util.concurrent包中,是JDK开发包的核心.其中有一个重要的类:Executors,他扮演这线程工厂的角色,我们通过Executors可以创建特定功能的线程池. newFixedThreadPool()方法,该方法返回一个固定数量的线程池,该方法的线程数始终不变,当有一个任务提交时,如线程池中有空闲,则立即执行,如没有,则会被暂缓在一个任务队

JDK线程池的使用

转载自:https://my.oschina.net/hosee/blog/614319: 摘要: 本系列基于炼数成金课程,为了更好的学习,做了系列的记录. 本文主要介绍: 1. 线程池的基本使用 2. 扩展和增强线程池 3. ForkJoin 1. 线程池的基本使用 1.1.为什么需要线程池 平时的业务中,如果要使用多线程,那么我们会在业务开始前创建线程,业务结束后,销毁线程.但是对于业务来说,线程的创建和销毁是与业务本身无关的,只关心线程所执行的任务.因此希望把尽可能多的cpu用在执行任务上