多线程
一、并发与并行
并发: 在一段时间内多个进程轮流使用同一个CPU,多个进程形成并发。
并行: 在同一个多个进程使用各自的cpu,多个进程形成并发。并行需要多个cpu支持。
理解:并行指同一时间点执行多个任务;并发指同一时间段中执行多个任务。
二、线程和进程
进程:是指一个内存中运行的应用程序(程序的一次运行就产生一个进程),每个进程都有自己独立的一块内存空间,比如在Windows的任务管理器中,一个运行的xx.exe就是一个进程。
线程:是指进程中的一个执行任务(控制单元),一个进程中可以运行多个线程,多个线程可共享进程的数据。
多线程:在同一各进程中并发运行的多个子任务。
一个进程至少有一个线程,为了提高CPU的效率,可以在一个进程中开启多个控制单元,这就是多线程。
三、同步和异步
同步:单线程执行,多线程串行执行。
异步:在多线程场景下,主线程继续处理任务,额外的任务交由异步线程处理,实现任务并行处理。
理解:同步是指一个进程在执行某个请求的时候,若这个请求没有执行完成,那么这个进程将会一直等待下去,直到这个请求执行完毕, 才会继续执行下面的请求。 异步是指一个进程在执行某个请请求的时候,如果这个请求没有执行完毕,进程不会等待,而是继续执行下面的请求。
四、线程安全
Java中线程安全体现在以下三个方面:
原子性:提供互斥访问,同一时刻只能有一个线程对数据进行操作。
可见性:一个线程对主内存的修改可与及时地被其他线程看到
有序性:一个线程观察其他线程中的指令执行顺序,由于指令重排序,该观察结果一般杂乱无序
因此,只要满足上述三个条件,我们就可以说该代码是线程安全的。那么,Java中提供了如下解决方案:
1. 使用sychronized关键字
- 使用线程安全类,如:java.util.concurrent包下的类
- 使用并发包下Lock相关锁
总结:想要代码满足线程安全 , 只需要代码满足原子性、可见性、有序性即可。
五、线程的创建
1. 继承Thread类,重写run方法
2. 实现Runnable接口,重写run方法,实现Runnable接口的实现类的实例对象作为Thread构造函数的target
3. 通过Callable和FutureTask创建线程
4. 通过线程池创建线程
六、线程池ThreadPool
为什么需要线程池?
线程重复利用;避免无限创建线程,导致系统异常。
线程池中几个重要的参数
核心线程数(corePoolSize):
线程池中可同时运行的线程数,超过核心线程数的线程会进入等待队列。
最大线程数(maximumPoolSize):整个线程池中最多有多少线程。
任务队列(workQueue):用于存放超过核心线程数的线程。
拒绝策略(handler):
当线程池中的线程数超过最大线程数时,基于拒绝策略来决定如何处理这些线程,默认时抛异常。
七、生命周期
| 创建 | 线程被构建,但是还没有调用start()方法 |
|---|---|
| 就绪 | 处于就绪状态线程具备了运行条件,处于线程就绪队列,等待系统为其分配cpu |
| 运行中 | 在运行状态的线程执行自己的run方法中代码,直到等待某资源而阻塞或完成任务而死亡。 |
| 阻塞 | 表示线程阻塞与锁。 |
| 终止 | 表示当前线程已经执行完毕。 |
八、线程同步方案
同步锁(Synchronized)
JUC的锁(Lock)
Object 的wait/notify
九、Java锁类型
内置锁:Synchronized
JUC: Lock