关于java并发:Java并发编程的艺术一书知秋

54次阅读

共计 4105 个字符,预计需要花费 11 分钟才能阅读完成。

前言

最近又把《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 的,不过还是有很多值得学习的常识!

正文完
 0