J.U.C学习总结

[toc]

java 内存模型 Java memory model jMM

J.U.C学习总结_第1张图片
image.png
J.U.C学习总结_第2张图片
image.png

java 内存八种操作

image.png

lock >read > load > use> assing > store >write >unlock

线程安全

  • 定义
    当多个线程访问某一个类时,不管运行时环境何种调度方式或者这些进程如何交替执行,并且在主调用代码中不需要任何额外的同步或协同,这个类都能表现出正确的行为,那么这个就程这个类是线程安全的

  • 原子性

    • AtomicXXX CAS 实现类 Unsafe.compareAndSwapInt
    • AtomicAdder 对AtomicLong 的优化 64 需要拆成两个32 位处理
    • AtomicRerference 实现了compareAndSet方法
    • AtomicIntegerFiledUpdater 要更新的字段必须要volatile标记,非static
    • AtomicStampReference CAS的ABA问题 ,增加了一个数据版本号
      • synchronized: 依赖JVM
        • 修饰代码块 作用于调用的对象
        • 修饰方法 作用于调用的对象
        • 修饰静态方法 作用于所有对象
        • 修饰类 作用于所有对象
      • Lock:依赖特殊的CPU指令,代码实现,ReentrantLock
    • 原子性对比
      • synchronized : 不可中断,适合竞争不激烈,可读性好
      • Lock 可中断锁,多样化同步,竞争激烈时能维持常态
      • Atomic:竞争激烈时能维持常态,比lock性能好,只能同步一个值
  • 可见性

    • 导致共享变量在线程 间不可见的原因
      • 线程交叉执行
      • 重排序结合线程交叉执行
      • 共享变量更新后的值没有在工作内存与主内存间及时更新
    • JMM(Java内存模型) 关于synchronized的两条规定
      • 线程解锁前,必须把共享变量的最新值刷新到主内存
      • 线程加锁时,将清空工作内存中共享变量的值,从而使用共享变量时需要从主内存中重新读取最新的值(加锁与解锁是同一把锁)
    • volatile 通过屏障和禁止重排序优化来实现, 并不是原子操作,不能实现线程安全
      • 对volatile变量写操作时,会在写操作后面加入一条store屏障质量,将本地内存中的共享变量值刷新到主内存
      • 对volatile变量读操作时, 毁在在读操作前加入一条load屏障指令,从主内存中读取共享变量
  • 有序性

    • Java 内存模型中,允许编译器和处理器对指令进行重排序,但是重排序过程不会影响大单线程程序的执行,却会影响到多线程并发执行的正确性
    • volatile ,synchronize,lock
    • happens-before 原则,如果两操作次序不能从happens-before推导出来就不能保证他们有序性,cpu可以对他们任意排序
      • 程序次序规则: 一个线程内,按照代码顺序,书写在前面的操作先行发生于与书写在后面的操作
      • 锁定规则:一个unlock操作先行发生于后面对同一个锁的lock 操作
      • volatile变量规则:对一个变量的写操作 先行发生于后面对这个变量的操作
      • 传递规则: 如果操作A先行发生于操作B,而操作B又先行发生于操作C,则可以得出操作A先行发生于 操作C

      • 线程启动原则: Thread对象的start()方法先行发生于此线程的每一个动作
      • 线程中断原则:对线程interrupt()方法的调用先行发生于比中断线程检测到中断事件的发生
      • 线程终结规则:线程中所有的操作都先发生于线程的终止检查,我们可以通过Thread.join()方法结束.Thread.isAlive()的返回值手段检测到线程已经终止执行
      • 对象终结规则:一个对象的初始化完成先行发生于他的finalize()方法的开始

安全发布对象

  • 发布对象:使一个对象能够被当前范围之外的代码所使用
  • 对象逸出:一种错错误的发布,当一个对象还没有构造完成时,就使它被其他线程所见
  • 安全发布对象
    • 在静态初始化函数中初始化一个对象引用

      • 饿汉模式在类加载的时候初始化缺点
        • 私有构造函数逻辑过多会影响加载速度
        • 如果实例化的类没有被使用会浪费
      • 懒汉模式, sync也,双重检测会被cpu指令重排也是不安全的,需要使用volatile+双重检测
    • 净对象的引用保存到volatile类型域或者AtomicReference对象中

    • 将对象的引用保存到某个正确构造对象的final类型 域中

    • 净对象的引用保存到一个由锁保护的域中

    • 单例方法

      • 饿汉模式静态
      • 懒汉 volatile +代码同步+双重检测
      • 枚举
      • final不可变
  • 不可变对象
    • final
    • 引用不可变 Collections.unmodifiableMap()
    • 线程封闭
      • 什么是线程封闭?就是把对象封装到一个线程里,只有这个线程能够访问
      • ad-hoc 线封闭: 程序控制实现,最糟糕回来
      • 堆栈封闭: 局部变量,无并发问题
      • ThreadLocal 线程封闭,特别好的封闭方法, 要是记得释放资源,否则会内存泄露
        • 内部是一个map
        • key是当前线程名称,value就是要封闭的对象
    • 常见线程不安全
      • stringBuilder 不安全 stringbuffer 安全
      • SimpleDateFormat 不安全 DateTimeFormatter 线程安全,第三方joda-time
      • ArrayList HashSet HashMap 等Collects
      • 先检查后执行: if(condition(a)){ handle(a)}
    • 同步容器
      • ArraList -> Vector,Stack
      • HashMap -> HashTable (key,value都不能为null)
      • Collections.synchronizedXX(List,Set,Map)

J.U.C ,java util concurrent

  • 并发容器

    • ArrayList -> CopyOnWriteArrayList
    • HashSet, TreeSet -> CopyOnWriteArraySet ConcurrentSkipList支持自然排序
    • HasMap,TreeMap -> ConcurrentHashMap ,ConcurrentSkipListMap
  • 安全共享策略

    • 线程限制:一个被线程限制的对象,有线程独占,并且只能被占有他的线程修改
    • 共享只读:一个贡献只读的对象,在没有额外同步的情况下,可以被多个线程并发访问,但是任何一个线程都不能修改它
    • 线程安对象:一个线程安全的对象或者容器,在内部通过同步机制来保证线程安全,所以其他线程无需额外的同步就可以通过公共接口随意访问
    • 被守护对象:被守护对象只能通过获得特定的锁来访问

JUC AQS

  • AQS AbstractQueuedSynchronizer
    • 使用node实现了FIFO队列
    • 利用一个int类型表示状态
    • 使用方法是集成
    • 子类通过继承并通过他的方法管理状态 (acquier 和relese) 方法操纵状态
    • 可以同时实现排它锁和共享锁模式(独占,共享)
  • AQS 同步组件
    • CountDownLatch 线程计数

      • J.U.C学习总结_第3张图片
        image.png
    • Semaphore 信号量 可以控制并发数量

    ```
          final Semaphore semaphore = new Semaphore(20);
          
          ///线程
          semaphore.acquire(); // 获取一个许可
          semaphore.acquire(n); // 获取多个许可
          //操作
          semaphore.release(); // 释放一个许可
          semaphore.release(3); // 释放多个许可
          
          
          
          semaphore.tryAcquire() //尝试获取一个许可,如果获取不到就丢弃
          semaphore.tryAcquire(1,TimeUnit.SECONDS) //尝试获取一个许可,等1s,如果获取不到就丢弃
      ```
    
    • CyclicBarrier 多个线程计数
      • J.U.C学习总结_第4张图片
        image.png
      • 可以重置计数器
      • 达到条件后多个线程可以同步执行
    • ReentrantLock(可重入锁)与synchronize区别
      • 可重入性 ,基于计数器实现
      • r JDK实现,s JVM实现
      • jdk优化之前 r好,优化之后差不多基于CAS实现
      • 功能区别 r需要手动开关,jvm 自动
      • ReentrantLock 独有的功能
        • 可以指定公平锁,默认非公平锁
        • 提供了Condition ,可以分组唤醒
        • 提供能改改中断等待做的机制,locklocInterruptibly();
      • ReentrantReadWriteLock
      • StampedLock
    • Condition
    • FutureTask
      • callable 与runnable
        • callable 可以有返回,使用Future接收, futer.get();
      • Future 接口
      • FutureTask
    • Fork/Join 窃取算法 ,双端队列
      • J.U.C学习总结_第5张图片
        image.png
    • BlockingQueue
      • 常见实现
        • ArrayBlockingQueue
        • DelayQueue
        • LinkedBlockingQueue
        • PriorityBlockingQueue 必须是compar接口
        • SynchronousQueue 只能存放一个
      • 生产消费场景
      • J.U.C学习总结_第6张图片
        image.png
      • 四套方法
        J.U.C学习总结_第7张图片
        image.png

线程池

  • new Thread() 弊端

    • 每次new Thrand 性能差,
    • 缺乏统一管理,可以无限制新建线程,占用过度系统资源
    • 确少更多功能,例如多执行,定期执行,线程中断
  • 线程池好处

    • 重用存在的线程,减少对象的创建消亡的开销
    • 可以有效控制最大并发数,提高系统资源利用率,可以避免过多资源竞争,避免阻塞
    • 提供定时,定期,单线程,并发数控制
  • ThreadPoolExecutor

    • corePoolSize 核心线程数量
    • maximuumPoolSize 线程最大线程数
    • workQueue 阻塞队列
    • keepAliveTime
    • unit 时间单位
    • threadFactory 线程工厂
    • rejectHandler 拒绝 策略
      • 丢弃
      • 使用当前调用者线程执行
      • 丢弃old
      • 丢弃当前
  • 线程池状态

    • J.U.C学习总结_第8张图片
      image.png
  • 基础方法

    • execute() : 提交任务,交给线程池执行
    • submi(): 提交任务,能够返回执行结果 execute() +Future
    • shutdown(): 关闭线程池,等待任务执行完
    • shutdownNow(): 关闭线程池不等待任务执行完成
  • 监控方法

    • getTaskCount();
    • getCompletedTaskCount();
    • getPoolSize()
    • getActiveCount();
  • J.U.C学习总结_第9张图片
    image.png
  • Executor 框架接口
    • Executors.newCachedThreadPool();
    • Executors.newFixedThreadPool();
    • Executors.newScheduledThreadPool();
    • Executors.newSingleThradExecutor();
  • 线程池配置
    • cpu密集型任务,就需要进来压榨CPU,参考值可以设置为NCPU+1
    • IO密集型任务,参考值可以设置为2*NCPU

J.U.C 学习总结

J.U.C学习总结_第10张图片
image.png

你可能感兴趣的:(J.U.C学习总结)