Java并发编程
- Thread/Runnable/Thread线程组管理
- Executor框架
- Fork-Join框架
三种并发编程方式比较
线程组ThreadGroup:
- 线程的集合;
- 树形结构,大线程组可以包括小线程组;
- 可以通过enumerate方法遍历组内的线程,执行操作;
- 能有效管理多个线程,但是管理效率低 ;
- 任务分配和执行过程高度耦合;
- 重复创建线程、关闭线程操作,无法重用线程;
Executor框架:
- 分离任务的创建和执行者的创建;
- 线程重复利用;
- 共享线程池
- 预设好的多个Thread,可弹性增加
- 多次执行很多很小的任务
- 任务创建和执行过程解耦
- 程序员无需关心线程池执行任务过程
主要使用的类:
- Executors.newCachedThreadPool/newFixedThreadPool 创建线程池
- ExecutorService 线程池服务
- Callable (需要实现的接口)具体的逻辑对象(线程类)
- Future 返回结果
Fork-Join框架:
- Java7提出,分解、治理、合并(分治编程),适用于整体任务量不好确定的场合
关键类:
- ForkJoinPool 任务池
- RecursiveAction
- RecursiveTask
并发数据结构
List
- Vector 同步安全,写多读少
- ArrayList 不安全
- Collections.synchronizedList(List list) 基于synchornized,效率差
- CopyOnWriteArrayList 读多写少,基于复制机制,非阻塞
Set
- HashSet 不安全
- Collections.synchronizedSet(Set set) 基于synchornized,效率差
- CopyOnWriteArraySet(基于CopyOnWriteArrayList实现)读多写少,非阻塞
Map
- Hashtable 同步安全,写多读少
- HashMap 不安全
- Collections.synchronizedMap(Map map) 基于synchornized,效率差
- ConcurrentHashMap 读多写少,非阻塞
Queue & Deque
- ConcurrentLinkedQueue 非阻塞
- ArrayBlockingQueue/LinkedBlockingQueue 阻塞
并发协作控制
线程协作
- Thread/Executor/Fork-Join:线程启动➡运行➡结束,线程之间缺少协作
- synchornized同步:限定只有一个线程才能进入临界区,简单粗暴,性能损失大
Lock
- 可以实现更加复杂的临界区结构
- tryLock方法可以预判断锁是否空闲
- 允许读写分离,多个读,一个写
- 性能好
- RunnableLock类,可重入的互斥锁
- ReentrantReadWriteLock类,可重入的读写锁
- lock和unlock函数
Senaphore
- 信号量大于0,可以使用,等于0不能使用
- 可以设置多个并发量,限制访问个数
- accquire 获取
- release 释放
- 比Lock更进一步,可以控制多个同时访问临界区
Latch
- 等待锁,是一个同步辅助类
- 用来同步执行任务的一个或多个线程
- 不是用来保护临界区或临界资源
- CountDownLatch类
- countDown() 计数减一
- await() 等待latch变成0
Barrier
- 集合点,也是一个同步辅助类
- 允许多个线程在某一个点上进行同步
- CyclicBarrier类
- 构造函数是需要同步的线程数量
- await ()等待其他线程,到达数量后,放行
Phaser
- 允许执行并发多阶段任务,同步辅助类
- 在每一个阶段结束的位置对线程进行同步,当所有的线程都达到这步,再进行下一步
- Phaser类:
- arrive()
- arriveAndAwaitAdvance()
Exchanger
- 允许在并发线程中互相交换消息
- 允许在2个线程中定义同步点,当两个线程都达到同步点,它们交换数据
- Exchanger类:
- exchange(),线程双方交换数据
- 交换数据是双向的