java并发.md

Java 并发

概念

thread

  • Runnable 无返回值

  • Callable -> Future

  • Executors

    • 可以实现将 Runnable 对象转换成 Callable 对象
    • Executors.callable(Runnable task)
  • ExecutorService 线程池的接口

    • ThreadPoolExecutor
      • 强制线程池不允许使用 Executors 去创建
    • newCachedThreadPool
      • 移除那些已有 60 秒钟未被使用的线程
    • newFixedThreadPool
      • 创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程
    • newScheduledThreadPool
    • newSingleThreadExecutor
      • 这个线程池只有一个线程
      • 这个线程池可以在线程死后(或发生异常时)重新启动一个线程来替代原来的线程继续执行下去
  • BLOCKED

    • io.wait()
    • lock
    • sleep
    • join
      • 等待其他线程 die
    • interrupt
      • 调用 interrupt()方法并不会中断一个正在运行的线程
        • 线程的 run 方法内部可以根据 thread.isInterrupted()的值来优雅的终止线程
      • 给这个线程一个通知信号,会影响这个线程内部的一个中断标识位
        • 这个线程本身并不会因此而改变状态(如阻塞,终止等)。

lock

  • 乐观锁
    • java 中的乐观锁基本都是通过 CAS 操作实现的
      • 在更新的时候会判断一下在此期间别人有没有去更新这个数据
      • 采取在写时先读出当前版本号,然后加锁操作(比较跟上一次的版本号,如果一样则更新)
        • 如果失败则要重复读-比较-写的操作
      • CAS 是一种更新的原子操作(硬件来实现), 比较当前值跟传入值是否一样,一样则更新,否则失败
      • 在使用 CAS 前要考虑清楚"ABA"问题是否会影响程序并发的正确性
        • 如果需要解决 ABA 问题,改用传统的互斥同步可能会比原子类更高效
        • 使用 AtomicStampedReference 是通过加版本号来解决 CAS 的 ABA 问题
      • 只能保证一个共享变量的原子操作
  • 悲观锁
    • synchronized
      • 可重入锁
      • 非公平锁
      • 每个对象都有一个 monitor, 加锁就是在竞争 monitor
      • 1.7/1.8 在对象头中有标记位, 不需要经过操作系统加锁
      • 锁膨胀
        • 偏向锁 -> 轻量级锁 -> 重量级锁
    • AQS 框架下的锁先尝试 CAS 乐观锁去获取锁, 获取不到, 转换为悲观锁
      • ReentrantLock
        • 可中断, 公平锁, 多个锁
        • conn.await / conn.signal
        • wait / notify
      • Semaphore 信号量
        • acquire -> ReentrantLock.lockinterruptibly (可中断)
      • AtomicReference
        • AtomicInteger/ AtomicLong
      • ReentrantReadWriteLock。
  • 自旋锁
    • 让 CPU 空旋等待
      • 适用于锁竞争不激烈的场景
    • 1.6 引入适应性自旋锁
  • 锁的状态总共有四种 (锁只能单向升级)
    • 无锁状态
    • 偏向锁
      • 在只有一个线程执行同步块时进一步提高性能
    • 轻量级锁
      • 在线程交替执行同步块时提高性能
    • 重量级锁
      • 存在同一时间访问同一锁的情况,就会导致轻量级锁膨胀 为重量级锁
  • 锁的优化
    • 只有在有线程安全要求的程序上加锁
    • 将大对象(这个对象可能会被更多线程访问), 拆成小对象
      • 分段锁
        • ConcurrentHashMap
    • 根据场景进行分离
      • 读写锁
    • 锁时间粗化
      • 为了提高并发, 原则上应该让每个线程持有锁的时间尽量短
      • 如果对同一个锁不停的进行请求、同步和释放,其本身也会消耗系统宝贵的资源,反而不利于性能的优化
  • ReentrantLock 比 synchronized 的优势
    • 等待可中断
      • lock.lockInterruptibly
      • 正在等待的线程可以选择放弃等待,改为处理其他事情
    • 可实现公平锁
      • 公平锁就是先等待的线程先获得锁
      • ReentrantLock 默认情况是非公平的
      • synchronized 只能是非公平锁
    • 可实现选择性通知
      • 线程对象可以注册在指定的 Condition 中,从而可以有选择性的进行线程通知,在调度线程上更加灵活
  • valatile
    • valatile 关键字线程同步的轻量级实现, 只能用于变量, 不能保证数据的原子性 (解决多线程之间的可见性)
    • synchronized 关键字解决的是多个线程之间访问资源的同步性

并发的 3 个特性

  • 原子性
    • synchronized 保证代码片段的原子性
  • 可见性
    • volatile 解决共享变量在多个线程之间的可见性
  • 有序性
    • volatile 禁止指令进行重排序优化