编程体系结构(05):Java多线程并发
一、多线程导图
二、多线程基础
1、基础概念
线程是操作系统能够进行运算调度的最小单位,包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
2、创建方式
继承Thread类、实现Runnable接口、基于Callable和Future接口、Timer是后台线程、线程池。
3、线程状态
状态描述:初始状态、运行状态、阻塞状态、等待状态、超时等待状态、终止状态。
4、执行机制
JVM中一个应用是可以有多个线程并行执行,线程被一对一映射为服务所在操作系统线程,调度在可用的CPU上执行,启动时会创建一个操作系统线程;当该线程终止时,这个操作系统线程也会被回收。
5、内存模型
在虚拟机启动运行时,会创建多个线程,数据区中有的模块是线程共享的,有的是线程私有的:
线程共享:元数据区、堆Heap;
线程私有:虚拟机栈、本地方法栈、程序计数器;
单个CPU在特定时刻只能执行一个线程,所以多线程通过几块空间的使用,然后不断的争抢CPU的执行时间段。
三、常见概念
1、线程优先级
线程调度器倾向执行线程优先级高的线程,线程优先级高说明获取CPU资源的概率高,或者获取的执行时间分片多,被执行的概率高但不代表优先级低的一定最后执行。
2、守护线程
守护线程是支持辅助型线程,主要在程序中起到调度和支持性作用,当Jvm中非守护线程全部结束,守护线程也就会结束。
3、线程加入
线程A中,执行线程B的加入方法,那么A线程就会等待线程B执行完毕再返回继续执行。
4、本地线程
ThreadLocal也叫做线程本地变量,为变量在每个线程中的创建副本,每个线程可以访问自己内部的副本变量,线程之间互不相互影响。
四、线程安全
在上图线程与内存空间的占用方式看,在线程访问共享内存块时,保证线程安全就很有必要。
1、同步控制
Synchronized关键字同步控制,可以修饰方法,修饰代码块,修饰静态方法等,同步控制的资源少,可以提高多线程效率。
2、加锁机制
Lock接口:Java并发编程中资源加锁的根接口之一,规定了资源锁使用的几个基础方法。
ReentrantLock类:实现Lock接口的可重入锁,即线程如果获得当前实例的锁,并进入任务方法,在线程没有释放锁的状态下,可以再次进入任务方法,特点:互斥排它性,即同一个时刻只有一个线程进入任务。
Condition接口:描述可能会与锁有关联的条件变量,提供了更强大的功能,例如在线程的等待/通知机制上,Conditon可以实现多路通知和选择性通知。
3、Volatile关键字
volatile修饰成员变量,不能修饰方法,即标识该线程在访问这个变量时需要从共享内存中获取,对该变量的修改,也需要同步刷新到共享内存中,保证了变量对所有线程的可见性。
五、线程通信
线程是个独立的个体,但是在线程执行过程中,如果处理同一个业务逻辑,可能会产生资源争抢,导致并发问题,甚至死锁现象,线程之间协调工作,就需要通信机制来保障。
1、基础方法
相关方法是Java中Object层级的基础方法,任何对象都有该方法:notify()随机通知一个在该对象上等待的线程,使其结束wait状态返回;wait()线程进入waiting等待状态,不会争抢锁对象,也可以设置等待时间;
2、等待/通知机制
等待/通知机制,该模式下指线程A在不满足任务执行的情况下调用对象wait()方法进入等待状态,线程B修改了线程A的执行条件,并调用对象notify()或者notifyAll()方法,线程A收到通知后从wait状态返回,进而执行后续操作。两个线程通过基于对象提供的wait()/notify()/notifyAll()等方法完成等待和通知间交互,提高程序的可伸缩性。
3、管道流通信
管道流主要用于在不同线程间直接传送数据,一个线程发送数据到输出管道,另一个线程从输入管道中读取数据,进而实现不同线程间的通信。
六、线程池
1、Executor接口
Executor系统中,将线程任务提交和任务执行进行了解耦的设计,Executor有各种功能强大的实现类,提供便捷方式来提交任务并且获取任务执行结果,封装了任务执行的过程,不再需要Thread().start()方式,显式创建线程并关联执行任务。
2、核心参数
3、相关API类
线程池任务:核心接口:Runnable、Callable接口和接口实现类;
任务的结果:接口Future和实现类FutureTask;
任务的执行:核心接口Executor和ExecutorService接口。在Executor框架中有两个核心类实现了ExecutorService接口,ThreadPoolExecutor和ScheduledThreadPoolExecutor。
七、常用线程API
1、Fork/Join机制
Fork/Join框架用于并行执行任务,核心的思想就是将一个大任务切分成多个小任务,然后汇总每个小任务的执行结果得到这个大任务的最终结果。核心流程:切分任务,模块任务异步执行,单任务结果合并。
2、容器类
ConcurrentHashMap:使用分段锁机制,把容器中数据分成一段一段的方式存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问,即考虑安全性也顾及执行效率。
ConcurrentLinkedQueue:基于链接节点的无界线程安全队列,按照FIFO先进先出原则对元素进行排序,队列的头部 是队列中时间最长的元素,队列的尾部是队列中时间最短的元素,新的元素添加到队列的尾部,获取元素操作从队列头部得到。
3、原子类
JDK自带原子操作类,处理多个线程同时操作一个变量的情况,其中包括:基本类型、数组类型、引用类型、属性修改类型。
八、应用场景
1、定时任务
通过配置设置一些程序在指定时间点,或者周期时间内规律循环执行,这里任务的执行就是基于多线程技术。
2、异步处理
异步处理就是不按照当前同步代码块程序执行,异步处理与同步处理是对立的,异步的实现也需要多线程或者多进程,提高程序效率。
3、任务分解
分布式数据库中常见操作,数据分布在不同的数据库的副本中,在执行查询时,每个服务都要跑查询任务,最后在一个服务上做数据合并,或者提供一个中间引擎层,用来汇总数据,在大型的定时任务中,经常把要处理的任务按照特定策略分片,多个线程同时处理。
4、连接池技术
创建和管理一个连接的缓冲池的技术,这些连接准备好被任何需要它们的线程使用,减少连接不断创建和释放的问题,提高程序效率。