JDK并发包

JDK并发包

同步控制

重入锁(ReentrantLock)

RenntrantLock通过lock()和unlock()来手动加锁, 所以在灵活性上要比synchronized好很多, 但是必须要记得释放锁, 不然会导致其他线程没有机会访问临界区, 另外, ReentrantLock的锁可以重复加锁, 但是必须也要释放同样多的锁.

另外重入锁还提供以下多个功能

  • 中断响应: 可以手动中断线程
  • 锁申请等待限时: 通过tryLock()来限时重试
  • 公平锁

以下可以通过如下函数实现:
lock(): 获得锁, 如果已经被占用, 则等待.
lockInterruptibly(): 获得锁, 但优先响应中断.
tryLock(): 尝试获得锁, 立即返回不等待, 成功: true, 错误: false;
tryLock(long time, TimeUnit unit): 规定时间内重试
unlock(): 释放锁.
重入锁的实现原理

  • 原子状态: 重入锁采用CAS操作来存储当前锁的状态.
  • 等待队列: 所有没有请求到锁的线程, 会进入等待队列进行等待.
  • 阻塞原语: park()和unpark()用于挂起和恢复线程.

信号量(Semaphore)

无论是内部锁synchronized还是ReentrantLock, 一次都只允许一个线程访问一个资源, 而信号量却可以指定多个线程, 同时访问某个资源

有如下两个构造参数:
public Semaphore(int permits)
public Semaphore(int permits, boolean fair) // 第二个参数指定是否公平
主要函数有如下:
public void acquire() // 尝试获得准入许可, 如无法获得, 那么就会等待, 知道有线程释放一个许可或, 当前线程被中断.
public void acquireUniterruptibly() // 和acquire类似, 但是不响应中断.
public boolean tryAcquire() // 尝试获得许可, 成功返回true, 否则返回false.
public boolean tryAcquire(long timeout, TimeUnit unit)
public void release() // 释放一个许可.

ReadWriteLock读写锁

  • 读-读不互斥: 读读之间不阻塞.
  • 读-写互斥: 读阻塞写, 写不会阻塞读.
  • 写-写互斥: 写写互斥.
    在读操作远大于写操作的系统中, 读写锁可以发挥最大功效, 提升性能.

倒计时器: CountDownLatch

主线程await(), 多线程每触发一次coutDown(), 倒计时器就减一, 当其变为0时, 主线程才会继续执行.

循环栅栏: CyclicBarrier

作用和CountDownLatch类似, 但是更加复杂, 假如将计数器设置为10, 那么凑齐第一批10个线程后, 计数器会归零, 然后接着凑齐下一批10个线程.(具体原理见书P90)

线程阻塞工具类: LockSupport

线程复用: 线程池

每次创建一个线程, 在run()方法结束后, 如果直接回收线程, 会出现创建和销毁线程所用时间大于线程执行消耗的时间, 而且大量的线程也会导致OOM, 就算没有也会给GC带来很大压力, 延长GC停顿时间.

Java提供了一套Executor框架, 本质就是一个线程池, 其中ThreadPoolExecutor表示一个线程池, Executors类扮演了线程池工厂的角色, 通过Executors可以取得一个特定功能的线程池. 其中提供了五种线程池:

  • newFixedThreadPool(int nThread): 返回一个固定线程数量的线程池, 如果无空闲线程, 那么新的任务就会被放入任务队列中, 待空闲时执行.
  • newSingleThreadExecutor(): 返回一个只有一个线程的线程池, 和上一个一样, 有多的直接放入任务队列, 空闲时按先入先出的顺序执行.
  • newCachedThreadPool(): 返回一个可以根据实际情况调整数量的线程池, 数量不确定, 若有空闲线程可以复用, 优先使用可复用的线程, 若所有线程均在工作, 又有新任务提交, 那么会创建新线程处理, 所有线程在当前任务执行完后, 返回线程池复用.
  • newSingleThreadScheduledExecutor(): 返回一个ScheduledExecutorService对象, 线程池大小为1, ScheduledExecutorService接口在ExecutorService接口之上扩展了在给定时间执行某任务的功能, 如固定延迟之后执行, 或周期执行.
  • newScheduledThreadPool(int corePoolSize): 也返回一个ScheduledExecutorService对象, 但可以指定其中线程数量.

线程池内部实现:

五种线程池, 其内部其实都使用了ThreadPoolExecutor实现, 其构造函数如下:
public ThreadPoolExecutor(int corePoolSize,
                        int maximumPoolSize,
                        long keepAliveTime,
                        TimeUnit unit,
                        BlockingQueue workQueue,
                        ThreadFactory threadFactory,
                        RejectedExecutionHandler handler)

其中函数参数含义如下:

  • corePoolSize: 线程池中的线程数量.
  • maximumPoolSize: 线程池中最大线程数量.
  • keepAliveTime: 当线程池线程数量超过corePoolSize时, 多余空闲线程存活时间.即超过CorePoolSize的空闲线程多久被销毁.
  • unit: keepAliveTime的单位.
  • workQueue: 任务队列, 被提交但尚未被执行的任务.
  • threadFactory: 线程工厂, 用于创建线程, 一般默认即可.
  • handler: 拒绝策略, 当任务太多时, 如何拒绝.

比如以下例子:
[图片上传失败...(image-c3a06e-1554900086425)]

以上参数当中, 有两个需要注意: workQueue和handler
参数workQueue指被提交但未执行的任务队列, 是一个BlockingQueue接口对象, 仅用于存放Runnable对象, 根据功能分类, 有如下几种BlockingQueue.

  • 直接提交的队列(SynchronousQueue): 是一个特殊的BlockingQueue, 没有容量, 每个插入操作都要等待一个删除操作, 每个删除操作也要等待一个插入操作, 提交的任务不会被保存, 而是直接交给线程执行, 如果没有空闲线程, 那么直接创建新的线程, 所以通常要设置很大的maximumPoolSize值.

  • 有界的任务队列(ArrayBlockingQueue): 使用时必须带一个容量参数表示队列的最大容量, 当线程池实际线程数量小于corePoolSize, 会优先创建新的线程, 若大于corePoolSize, 那么会加入等待队列, 假如等待队列也满了, 且不大于maximumPoolSize, 才会创建新的线程, 大于maximumPoolSize会直接执行拒绝策略, 所以只有任务队列满的时候, 线程数才有可能超过corePoolSize, 换言之, 除非系统特别繁忙, 不然一般线程数都维持在corePoolSize.

  • 无界的任务队列(LinkedBlockingQueue):与有界队列不一样的是, 无界不是出现入队失败的情况, 当线程数小于corePoolSize的时候, 会生成新线程执行, 当达到corePoolSize的时候, 就不会增加, 直接进入队列等待, 当任务创建和处理速度差太多的时候, 队列会大量阻塞, 一直增长, 直到耗尽内存.

  • 优先任务队列(PriorityBlockingQueue): 带优先级的队列, 是一种特殊的无界队列, 确保系统性能的同时, 按照优先级来执行.

    [图片上传失败...(image-d8bf73-1554900086426)]
    [图片上传失败...(image-325ef6-1554900086426)]

handler: 拒绝策略

JDK内置了4种策略

  • AbortPolicy策略: 直接抛出异常, 阻止系统正常工作.
  • CallerRunsPolicy策略: 只要线程池没关闭, 会直接在调用者线程执行丢弃的任务, 但是这样会让任务提交线程的性能下降.
  • DiscardOledersPolicy: 丢弃最老的一个请求, 也就是即将被执行的请求, 然后尝试再次提交当前任务.
  • DiscardPolicy: 直接丢弃无法处理的任务.

扩展线程池和threadFactory的自定义, 堆栈的改造

你可能感兴趣的:(JDK并发包)