Java并发编程

Java并发编程(未完成,待继续)

最近学习了网易云课堂中的Java高性能编程课程,结合之前的一些学习和积累,希望通过本文对Java并发编程相关的知识做一个梳理,构建Java并发编程的知识体系。咳咳,本篇文章是我的第一篇创作,主要是为了帮助自己系统性的梳理Java并发编程先关的知识,如果有其他看客路过,欢迎进行分享和交流~~

正式开写前先说两点:

  1. 本文并不是进行知识的原创,而是对知识进行梳理,以形成体系。因此,文章本身可能更类似于大纲性质的知识描述,但在具体知识点上会提供相关的链接以便学习。换句话说,本文不生产知识,只是知识的搬运工。当然,分享的知识有好有坏,欢迎路过的看客能够分享更加优质的资源,先谢过了~~
  2. 基于第一点再说明下:学习知识 or 生产知识很重要,而梳理知识并形成知识体系也很重要,个人认为甚至更加重要。所以,我更希望自己能够梳理知识&构建体系,并针对具体的知识点提供相关连接,仅在必要的时候,自己才考虑知识的原创(希望不会有,嘎嘎~~)。当然,我知道对知识进行梳理并不简单,希望自己能够做的尽量好。

最后再强调下,互联网上的牛人很多,生产的优质资源也很多,我并不是其中之一,但是希望自己能够站在巨人的肩膀上!

OK,开工~~

本文主要对Java并发编程相关的知识点尝试总结和梳理,主要围绕“并发编程的基础”、“并发程序存在的问题”、“并发编程需要解决的问题”、“高性能并发编程”、“Java并发工具”、“Java并发容器”几个方面进行说明。具体如下:
并发编程的基础:Java并发程序的基础是线程,只有多线程才会产生并发,所以这一部分主要对Java线程进行了梳理,涉及Java线程模型、线程状态、线程创建&终止、线程池等知识。
并发程序存在的问题:这一部分描述了并发程序天然存在的3大问题(原子性、可见性、有序性),旨在让我们进行并发编程的过程中意识到这些问题,避免踩坑。同时,针对这3大问题,介绍了Java是如何解决的。
并发编程需要解决的问题:这一部分描述了我们在进行并发编程时面临的3个核心问题(分工、同步、互斥),以及我们如何解决这3个问题,搞定并发编程。
高性能并发编程:采用并发编程的目的是为了提高执行程序的性能,基于该点,本部分对如何进一步优化并发程序、提高程序性能进行了说明。主要涉及:如何合理创建线程、如何充分利用计算机资源、如何避免资源竞争、如何降低竞争开销 等几个方面。
Java并发工具&Java并发容器:这两部分主要是介绍JDK为我们提供了哪些工具,以便我们更加高效的进行并发编程&编写出更高效的并发程序。

OK,针对这6大部分,我们的详细整理如下。

一、并发编程的基础:Java线程

1、线程模型:

Java线程模型一般为一对一的内核线程模型,实际实现过程中的线程模型有如下3种:

1)内核线程模型:依赖操作系统实现&实现简单&存在操作系统的限制&线程切换开销大

  • 一个用户线程对应一个轻量级进程(内核线程)
  • 线程的最大个数受到操作系统限制
  • 线程的调度完全依赖操作系统
  • 线程的切换涉及到用户态与内核态的切换

2)用户线程模型:不依赖操作系统&实现复杂&线程切换开销低

  • 多个用户线程对应一个进程
  • 线程的最大个数由线程库的实现决定,能够支持大规模的线程数量
  • 需要创建一个线程库,实现一套线程的创建、同步、销毁、调度机制,实现难度大
  • 线程的切换不涉及用户态到内核态的切换,性能高

3)混合线程模型

  • N个用户线程对应M个轻量级进程(内核线程)
  • 线程的最大个数由线程库的实现决定,能够支持大规模的线程数量
  • 需要创建一个线程库,但可以使用系统内核提供的线程调度及处理器映射等功能,实现难度有所降低
  • 线程的切换可能涉及到用户态与内核态的切换,也可能不涉及,性能较高
    参考资料 https://www.cnblogs.com/kaleidoscope/p/9598140.html

2、线程状态&状态转换:

Java线程的线程状态包括:New、Runnable、Blocked、Waiting、Timed Waiting、Terminated,线程状态之间的转换如下图。(待补充

参考资料 https://blog.csdn.net/shi2huang/article/details/80289155https://www.jianshu.com/p/979ba2f919e3

3、线程创建方式:

1)继承Thread,重写run方法
2)实现Runnable接口及run方法,以Runnalbe实例为参数,创建Thread实例
3)实现Callable接口及call方法,以Callable实例为参数,创建FutureTask实例,再以FutureTask实例为参数,创建Thread实例。相比于前两个方式,第3个方式能够获取线程的执行结果或异常信息
4)利用线程池&提交任务的方式创建线程,结合 Executors/ThreadPoolExecutor/ExecutorService、Runnable、Callable、FutureTask等实现
5)通过Fork/Join框架创建线程,结合ForkJoinPool、ForkJoinTask等实现

参考资料 https://www.cnblogs.com/felixzh/p/6036074.html

4、线程挂起方式:

1)使用suspend&resume进行线程的挂起和唤醒

  • 已被弃用,因为不安全、易导致死锁
  • 使用时suspend方法必须在resume方法之前被执行
  • suspend方法将线程挂起后不会释放锁。

2)使用wait&notify/notifyAll进行线程的挂起和唤醒

  • wait方法必须在notify/notifyAll方法之前被执行,否则线程会一直处于Waiting状态
  • 使用时需要配合synchronized关键字使用
  • 执行wait方法时会自动释放锁,并且被唤醒后会重新获得锁。

3)使用LockSupport.park&unpark进行线程的挂起和唤醒

  • 对两个方法执行的先后顺序没有要求,但是unpark的执行效果不会叠加,即多次调用unpark后,第一次调用park方法时线程不会挂起,但是第二次线程会挂起,可以理解为期间只是设置了一个标记位,没有叠加效果
  • park方法不会释放锁,如果结合synchronized关键字使用时,要注意避免死锁问题。

4)使用Lock&Condition进行线程的挂起和唤醒:第4种方法是基于第3种方法实现的。

注意:实际编码的过程中,需要关注“伪唤醒”问题。所谓的“伪唤醒”是指线程并非由于notify、notifyAll、unpark等api调用而被唤醒,而是更加底层的原因导致,所以建议通过使用“循环+等待条件检查”来避免“伪唤醒”问题。
参考资料 (待补充

5、线程终止的方式:

1)Thread的stop方法:强制终止线程的执行。该方法可能会打破线程执行的原子性,导致线程安全问题,如线程执行synchronized代码块的过程中被stop,会破坏代码块的原子性。

2)Thread的interrupt方法–线程中断

  • 该方法会设置线程的中断标志,但并不会终止线程的处理,实际使用的过程中,需要主动在代码中检查线程的中断标志并中断线程的处理
  • 在线程处于非Blocked状态下执行interrupt方法时,会正常设置线程的中断标志
  • 在线程处于Blocked状态下(wait、join、sleep…)执行interrupt方法时,线程的中断标志在设置后会被清除,同时抛出InterruptedException异常

3)标志位法

  • 代码逻辑中,增加一个判断,用来控制是否终止线程的执行
  • 线程的执行逻辑应为 while+终止条件判断

参考资料 (待补充

6、线程池:

1)什么是资源的池化?池化模型的作用?
主要是针对可以重复利用的资源,创建一个资源池将其保存起来,避免重复创建和释放资源带来的开销。常见的有对象池、线程池、数据库连接池等。

2)JDK提供的线程池

  • 线程池的创建方式:JDK提供的线程池创建类为ThreadPoolExecutor,对应的参数说明如下
    int corePoolSize–线程池的核心线程数
    int maximumPoolSize–线程池的最大线程数
    long keepAliveTime–非核心线程空闲时的最大存活时间
    TimeUnit unit–存活时间的时间单位
    BlockingQueue workQueue–任务队列,用于存储等待执行的任务的队列
    ThreadFactory threadFactory–线程工厂,用于创建线程,一般默认即可
    RejectedExecutionHandler handler–拒绝策略,当提交的任务过多而无法处理时,会使用拒绝策略处理提交的任务
  • 4种默认的线程池:实际上是基于ThreadPoolExecutor进行了一些包装
    Executors.newCachedThreadPool–线程池的大小无限制,任务队列为有界队列
    Executors.newFixedThreadPool–线程池的大小固定,任务队列为无界队列
    Executors.newSingleThreadPool–线程池的长度为1,任务队列为无界队列
    Executors.newScheduledThreadPoolExecutor–线程池的大小无限制,任务队列为无界队列,可定时或周期性执行任务
  • 4中默认的拒绝策略
    ThreadPoolExecutor.AbortPolicy–丢弃任务并抛出RejectedExecutionException异常
    ThreadPoolExecutor.DiscardPolicy–丢弃任务,但是不抛出异常
    ThreadPoolExecutor.DiscardOldestPolicy–丢弃最老的任务,将新的任务加入到等待队列
    ThreadPoolExecutor.CallerRunsPolicy–由调用线程处理该任务,线程池不进行处理
  • 任务提交方式
    execute–线程池执行完任务后,不会有返回信息,也拿不到异常信息
    submit-- 可用于在线程池执行完任务后,获取执行结果或异常信息

3)线程池的执行逻辑

  • 线程数小于核心线程数时,创建线程执行任务
  • 线程数大于核心线程数&任务队列未满时,任务进入队列进行等待
  • 线程数大于核心线程数&任务队列已满&线程数小于最大线程数时,创建线程执行任务
  • 线程数大于核心线程数&任务队列已满&线程数大于最大线程数时,执行拒绝策略

4)如何合理设置线程池的大小

  • 参见高性能并发编程小结的说明(CPU密集型任务、IO密集型任务)

参考资料 (待补充

=============================================================================== 华丽的分割线,下面的内容待完善

二、并发程序存在的问题:并发问题/多线程问题、3大源头

1、什么是并发问题

1)共享变量&非共享变量
2)栈封闭&ThreadLocal

2、并发问题的3大源头

1)哪三大问题:原子性问题、可见性问题、有序性问题
2)为什么会有这3大问题:编译优化&缓存

3、如何解决3大问题

1)原子性问题:锁,synchronized关键字 对比 Lock
2)可见性问题:volatile关键字、happens-before规则
3)有序性问题:volatile关键字、final关键字…
4)Java内存模型

三、并发编程需要解决的问题:分工、同步、互斥

1、任务分工:

Executor、Fork/Join、Future,生产者-消费者模式、Thread-Per-Message模式、Worker Thread模式

2、线程间的通信(同步):

1)文件共享
2)网络共享
3)变量共享(共享内存)
4)线程协作API(阻塞&唤醒)

  • suspend&resume
  • wait&notify/notifyAll
  • LockSupport.park&unpark
  • Lock&condition
  • 同步工具类:CountDownLatch、CyclicBarrier

3、资源的互斥访问(共享资源、共享变量):

1)无锁

  • 不可变量final
  • 线程本地变量-ThreadLocal(内存泄漏问题
  • COW
  • CAS无锁并发

2)互斥锁

  • synchronized
  • Lock
  • 读写锁
  • 死锁问题

四、高性能并发线程

1、尽可能的避免竞争

1)不可变模式
2)线程本地变量
3)COW

2、尽可能降低竞争开销

1)无锁并发(乐观锁&悲观锁)
2)降低加锁范围、减少锁的持有时间(粗粒度锁&细粒度锁)
3)读写锁(共享锁&排他锁)

3、尽可能提升资源利用率

1)创建合适的线程个数:CPU密集型任务、IO密集型任务
2)异步编程:Guarded Suspension模式、Future模式…
3)协程:降低线程的资源消耗&线程切换的消耗

4、扩展–高性能编程技术

1)资源池化
2)请求缓冲
3)请求聚合(合并)
4)数据缓存
5)任务拆解(多线程)
6)异步编程
7)负载均衡
8)分布式

五、Java并发工具类

1、分工

1)CompletableFuture
2)CompletionService
3)Fork/Join

2、同步

1)Lock&Condition
2)Semaphore
3)CountDownLatch
4)CyclicBarrier

3、互斥

1)ReadWriteLock
2)StampedLock

4、AQS

六、Java并发容器

1、List

1)CopyOnWriteArrayList

2、Map

1)ConcurrentHashMap
2)ConcurrentSkipListMap

3、Set

1)CopyOnWriteArraySet
2)CopyOnWriteSkipListSet

4、Queue

1)有界
a、ArrayBlockingQueue
b、LinkedBlockingQueue
c、SynchronousQueue
2)无界
a、PriorityBlockingQueue
b、DelayQueue
c、ConcurrentLinkedQueue

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值