Java并发编程的艺术--一书知秋

Posted 小橙子的快乐wu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java并发编程的艺术--一书知秋相关的知识,希望对你有一定的参考价值。

前言

最近又把《Java并发编程的艺术》这本书,重读了一遍,感觉收获比上一次还大!因为在实际的学校学习中,Java并发这一块,其实并没有很常用,但是恰恰不巧的事,在企业中在实际生产中,并发编程是不可或缺的一块,所以重读这本书我觉得很有必要。
最近感悟,学习是一件很快乐的事,每当读《Java并发》《JVM》时,感觉莫名的兴奋,对技术的热情还是有哒!我的《平凡的世界》还没有读完,wuwuw,等忙完这阵子也要补补了。

一、并发编程的挑战

1、上下文切换 (无锁并发编程(避免锁竞争),CAS算法,使用最少线程,协程)
2、死锁

  • 条件:1、互斥条件 2、不可剥夺条件 3、请求与保持条件 4、循环等待条件
  • 解决:1避免同时获得多个锁 2避免一个锁内使用多个资源 3尝试使用定时锁 4数据库锁加锁和解锁在一个链接里
  • Java:按序加锁、加锁时限、死锁检测(维护一个数据结构)

3、资源限制(硬件(上传下载 读写)(集群) 软件(连接数)(池化复用))

二、Java并发机制的底层实现

1、volatile

  • ①Lock前缀指令会引起处理器缓存写会主内存
  • ②处理器缓存写会主内存会使其他处理器的缓存失效

2、synchronized 1.6后优化

  • 无锁: 偏向锁标识为0,则CAS获取偏向锁
  • 偏向锁:偏向锁标识为1,锁对象记录线程ID,下次该线程获取时直接测试,失败则CAS尝试锁记录指向当前线程ID
  • 关闭偏向锁,直接进入轻量级锁
  • 轻量级锁:加锁:当前线程的栈帧中创建空间,对象头的MarkWord复制该空间,CAS尝试对象图的MW指向该空间,成功则获得锁,失败则自旋获取锁;解锁:CAS操作将栈帧中的锁记录Displaced MarkWoed替换回对象头,成功即解锁,失败则有竞争,膨胀为重量级锁,阻塞竞争线程,自己释放锁并唤醒竞争线程
  • 重量级锁:竞争线程阻塞,解锁后唤醒竞争线程

3、原子操作

  1. 锁(CAS方式释放获取锁)
  2. 自旋CAS(ABA(版本号)、循环开销、只保证一个共享变量的原子操作)

三、Java内存模型

  1. Java并发采用共享内存模式(消息传递模式)隐式通信显示同步
  2. 主内存存储共享变量 每个线程有本地内存保存主内存的共享变量副本

四、Java并发基础

    1、进程资源分配的最小单位、线程程序执行的最小单位
    2、线程的状态 
     new->runnable(running、ready)->terminated waiting|time_waiting|blocked
    3、中断线程interrupt 而不使用stop(不释放资源);也可在线程内部使用一个boolean变量 
    4、线程先获取监视器对象,获取失败则进入SynchronizedQueue wait->进入WaitQueue->notify->SynchronizedQueue
?    |5、t.join 当前线程进入wating态等待t线程执行完 涉及等待通知机制 给t加锁 让当前线程等待,t结束时唤醒当前线程
    6、ThreadLocal线程本地变量 数据库连接管理保证当前线程操作的Connection都为同一个
      ThreadLocal.set会在thread中ThreadLocalMap保存值,以ThreadLocal为键,value为值
      ThreadLocal.get会获取thread中的ThreadLocalMap以ThreadLocal取值
      ThreadLocalMap是ThreadLocal的内部类,被thread引用

五、Java中的锁

    1、Lock接口 非阻塞获取锁、超时获取锁、响应中断的获取锁
    2、AQS
        1定义同步组件,实现AQS,重写相应方法,同步组件调用AQS的模板方法即可
        2依赖同步队列完成同步状态的管理 同步队列中有节点保存获取同步线程失败的线程引用,等待状态 
         同步器包含头尾节点,首节点是获取同步状态成功的节点,释放同步状态时唤醒后继节点并设置为首节点

    3、重入锁:重复加锁而不被自己阻塞 ReentrantLock|Synchronized
     公平与非公平锁:是否请求顺序 ReentrantLock 
    4、读写锁ReentrantReadWriteLock 一个读多个写 维护一对读锁写锁 同步整型状态按位切割 锁降级(写->读)
    5、LockSupport工具 阻塞唤醒当前线程
    6、Condition(Lock.newCondition) 类似wait/notify 作为同步器的内部类,AQS引用多个Condition等待队列
      await同步队列首节点->等待队列尾结点 signal等待队列首节点->同步队列首节点

六、Java并发容器和框架

    1、ConcurrentHashMap 
     JDK7 segment[](继承自ReentantLockd)->数组+链表 get不加锁(volatile修饰) put加分段锁(判断是否扩容,单个Segment扩容)
     JDK8 数组+链表+红黑树 get不加锁 put时初始化,没有hash冲突直接CAS插入,有就synchronized锁住头结点插入
         put操作
             1数组为空则进行初始化
             2首节点为空则cas直接插入
             3需要扩容则协助扩容
                 扩容时多线程并发扩容helpTransfer 特殊首节点ForwardingNode表示已扩容过直接跳过
             4首节点加synchronized锁put
    2、线程安全队列 非阻塞(循环cas)|阻塞(锁)
    3、ConcurrentLinkedQueue无界线程安全队列 cas入队尾结点 cas出队列头结点
    4、阻塞队列BlockingQueue
        ArrayBlockingQueue 数组结构的有界阻塞队列(必须指定长度) 不保证公平访问
        LinkedBlockingQueue 链表结构的有界阻塞队列(可指定,默认长度为int_max) 
        PriorityBlockingQueue 支持优先级的无界阻塞队列(可扩容,长度最大也为int_max(queue为数组实现的堆))
        DelayQueue 延时获取元素的无界阻塞队列
        SynchronnousQueue 一个put对应一个take不存储元素
        LinkedTransferQueue 链表结构的无界阻塞队列
        LinkedBlockingQueue 链表结构组成的双向阻塞队列

        阻塞队列实现原理 等待通知模式 condition.await|signal->LockSupport.park|unpark(先保存当前线程再阻塞)->底层park|unpark

七、原子操作类

    原子更新基本类型 AtomicBoolean AtomicInteger AtomicLong(其他基本类型 转为int型)
     以AtomicInteger的getAndIncrement为例
         get()获取旧值 新值=旧值+1
         cas(旧值,新值)->unsafe的native方法
         循环直到成功
    原子更新数组 AtomicIntegerArray AtomicLongArray AtomicReferenceArray
    原子更新引用类型 AtomicReference AtomicReferenceFiledUpdatr AtomicMarkableReference
    原子更新字段类 AtomicIntegerFiledUpdater AtomicLongFiledUpdater AtomicStampedReference

八、Java中的并发工具类

    1、CountDownLatch替代join实现计数器
    2、CyclicBarrier 阻塞一批线程直到所有线程都完成,打开屏障
     下一步动作实施者不一样CountdownLatch为主线程 CyclicBarrier为其他线程
     CyclicBarrier 计数器可以重置 适合更复杂场景
    3、Semaphore 控制并发线程的数量 流控
    4、Exchanger 线程间交换数据

九、线程池

    1、实现原理
        execute提交任务
        核心线程池未满(即使有空闲,不销毁)则创建线程执行任务,已满则阻塞队列是否已满,未满则加入队列,已满则看线程池是否已满,未满则创建线程执行任务,已满则执行拒绝策略

        创建的线程封装为工作线程Worker,执行完从阻塞队列中获取任务
    2、new ThreadPoolExecutor(corePoolSize,maximumPoolSize,keepAliveTime,unit,workQueue,threadFactory,handler)
        corePoolSize 核心线程大小
        maximumPoolSize 最大线程数量
        keepAliveTime 空闲线程存活时间
        workQueue
            ArrayBlockingQueue
            LinkedBlockingQuene
            SynchronousQuene
            PriorityBlockingQueue
        threadFactory 线程工厂 主要定义名字
        handler 拒绝策略
            CallerRunsPolicy 调用者线程执行
            AbortPolicy 直接丢弃 抛出RejectedExecutionException异常
            DiscardPolicy 直接丢弃
            DiscardOldestPolicy 抛弃最早进入队列的任务,放进队列

    3、Executor框架
        ThreadPoolExecutor
            SingleThreadExecutor 1-1 LinkedBlockingQueue
            FixedThreadPool core-max LinkedBlockingQueue
            CacheThreadPool 0-max SynchronousQueue 不同创建线程
        ScheduledThreadPoolExecutor 比Timer更灵活
            ScheduledThreadPoolExecutor
                DelayQueue 内部是一个PriorityQueue把time小的优先 任务需要实现Delay接口
            SingleThreadScheduledExecutor
        Future 表示结果
        Runnable
        Callable
        Executors

总结

最近,没那么多时间来写博客了,只能简单的对重读的知识,进行总结,所以排版不是很好,有时间会回来优化的!

想了解并发编程的同学,十分建议《Java并发编程的艺术这本书》
不足在于,其是基于JDK1.7的,不过还是有很多值得学习的知识!

以上是关于Java并发编程的艺术--一书知秋的主要内容,如果未能解决你的问题,请参考以下文章

《java并发编程实战》

重磅!好友「知秋」的新书《Java编程方法论:响应式RxJava与代码设计实战》正式预售啦

并发编程艺术-锁类型以及底层原理

一文读懂响应式编程到底是什么?(附赠国外优质Java学习视频)

07深入理解Java线程池

读《Java并发编程的艺术》