Java并发 -- 概述
核心问题
分工
- JUC中的
Executor
、Fork/Join
和Future
本质上都是一种分工方法 - 并发编程领域还总结了一些设计模式,基本上都是和分工方法相关
- 生产者-消费者
Thread-Per-Message
Worker Thread
同步
- 在并发编程领域里的同步,主要指的就是_线程间的协作_
- 一个线程执行完了一个任务,如何通知执行后续任务的线程开始工作
- 协作一般是与分工相关的
- JUC中的
Executor
、Fork/Join
和Future
本质上都是一种分工方法 - 但同时也能解决线程协作的问题
- JUC中的
- 例如,用
Future
可以发起一个异步调用- 当主线程调用get()方法取结果时,主线程会等待
- 当异步执行的结果返回时,get()方法就自动返回了
Future
工具类已经帮我们解决了_主线程和异步线程之间的协作_
- JUC中的
CountDownLatch
、CyclicBarrier
、Phaser
和Exchanger
都是用来解决线程协作问题的 - 但很多场景还是需要自己处理线程之间的协作,问题基本可以描述为
- 当某个条件不满足时,线程需要等待,当某个条件满足时,线程需要被唤醒执行
- 在Java并发编程领域,解决协作问题的核心技术是管程(Monitor)
- 上面提到的所有线程协作技术底层都是利用管程来解决的
- 管程是一种解决并发问题的通用模型,除了能解决线程协作问题,还能解决互斥问题
- 管程是解决并发问题的万能钥匙
互斥
- 分工和同步主要强调的是性能,线程安全关注的是_并发程序的正确性_
- 在并发程序里,当多个线程同时访问同一个共享变量时,结果是不确定的
- 导致不确定的主要源头是可见性问题,有序性问题和原子性问题,为了解决这三个问题,Java引进来_Java内存模型_
- Java内存模型提供了一系列规则,可以避免可见性问题,有序性问题和原子性问题,但_不能完全解决线程安全的问题_
- 解决线程安全问题的核心方案还是互斥,互斥的定义:_在同一时刻,只允许一个线程访问共享变量_
- 实现互斥的核心技术是锁,
synchronized
、JUC中的各种Lock
都能解决互斥问题 - 锁解决了线程安全的问题,但同时也带来了性能问题,可以针对场景进行优化
- JUC中的
ReadWriteLock
、StampedLock
可以优化在读多写少的场景下锁的性能 - 无锁的数据结构,例如JUC中的原子类都是基于无锁技术实现的
- 使用
Copy-On-Write
模式 - 不共享变量(ThreadLocal)或者变量只允许读(final)
- JUC中的
- 使用锁除了要注意性能之外,还需要注意死锁问题
小结
参考资料
All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.