一.线程的理解
1.线程和进程
1.1.什么是进程
进程是资源(CPU、内存等)分配的基本单位,它是程序执行时的一个实例。程序运行时系统就会创建一个进程,并为它分配资源,然后把该进程放入进程就绪队列,进程调度器选中它的时候就会为它分配CPU时间,程序开始真正运行
PS:资源分配是你这个进程占用了多少CPU和内存等,分配给你这个进程
1.2.什么是线程
线程是程序执行时的最小单位,它是进程的一个执行流,是CPU调度和分派的基本单位,一个进程可以由很多个线程组成,线程间共享进程的所有资源,每个线程有自己的堆栈和局部变量。线程由CPU独立调度执行,在多CPU环境下就允许多个线程同时运行。同样多线程也可以实现并发操作,每个请求分配一个线程来处理。【代码都是靠线程去执行】
进程是资源分配的最小单位,线程是程序执行的最小单位。
2.线程三种方式
-
继承Thread类(无返回值)
-
实现Runnable接口(无返回值)
-
使用ExecutorService、Callable(有返回值)、Future实现有返回结果的多线程
实现 Runnable 和 Callable 接口的类只能当做一个可以在线程中运行的任务,不是真正意义上的线程,因此最后还需要通过 Thread 来调用。可以说任务是通过线程驱动从而执行的。
2.1实现接口 VS 继承 Thread
实现接口会更好一些,因为:Java 不支持多继承,因此继承了 Thread 类就无法继承其它类,但是可以实现多个接口;类可能只要求可执行即可,继承整个 Thread 类开销会过大。
2.2Thread和Runable的区别和联系
-
Thread类实现了Runable接口。都需要重写里面Run方法。
-
不同:实现Runnable的类更具有健壮性,避免了单继承的局限。
-
Runnable更容易实现资源共享,能多个线程同时处理一个资源
3.线程生命周期图
3.1.线程生命周期图
特别注意:当调用start后,线程拥有可执行的权限,但是不一定被执行,只有抢到CPU资源才是running运行状态
sleep是thread的方法,wait是object的方法 ;wait会释放锁,sleep不会。
3.2线程的状态
新建状态
使用 new 关键字和 Thread 类或其子类建立一个线程对象后,该线程对象就处于新建状态。它保持这个状态直到程序 start() 这个线程。
就绪状态
当线程对象调用了start()方法之后,该线程就进入就绪状态。就绪状态的线程处于就绪队列中,要等待JVM里线程调度器的调度。
运行状态
如果就绪状态的线程获取 CPU 资源,就可以执行 run(),此时线程便处于运行状态。处于运行状态的线程最为复杂,它可以变为阻塞状态、就绪状态和死亡状态。
阻塞状态
如果一个线程执行了sleep(睡眠)、suspend(挂起)等方法,失去所占用资源之后,该线程就从运行状态进入阻塞状态。在睡眠时间已到或获得设备资源后可以重新进入就绪状态。可以分为三种:
-
等待阻塞:运行状态中的线程执行 wait() 方法,使线程进入到等待阻塞状态。
-
同步阻塞:线程在获取 synchronized 同步锁失败(因为同步锁被其他线程占用)。
-
其他阻塞:通过调用线程的 sleep() 或 join() 发出了 I/O 请求时,线程就会进入到阻塞状态。当sleep() 状态超时,join() 等待线程终止或超时,或者 I/O 处理完毕,线程重新转入就绪状态。
死亡状态
一个运行状态的线程完成任务或者其他终止条件发生时,该线程就切换到终止状态。
二.线程池使用和原理(高频)
1.线程池(ThreadPoolExecutor )介绍
1.1.什么是线程池?
简答理解:就是有一个池子里面有很多个线程。
1.2.为什么用线程池
需要用线程池来管理线程,举个例子吧,车牌号限行就是车牌号一多就容易赌
补充:连接池和线程池其实本质都差不多,都是用的池化技术
PS:如果这个时候需要大量创建对象怎么办?大量频繁创建对象可以用工厂模式或者用池化技术
1.3.线程池执行流程
个人理解:核心线程→进入队列排队→创建新的线程→拒绝策略
比如任务来了,最开始由核心线程执行,然后任务再来了,核心线程用完了,它会排队,它不会创建新的线程,核心线程用完了它会排队,队列排满了,才会创建新的线程,但是新的线程的数量会受到最大核心线程所影响,这个时候核心、队列、非核心都满了用完了,它就会拒绝
☺