目 录
第一部分 线程基础
1. 概念简介
进程:指运行中的程序,如启动QQ、微信都是启动一个进程。
线程:由进程创建,是进程的一个实体。
一个进程可以有多个线程,一个线程中也可以创建另一个线程。
单线程:同一时刻,只允许执行一个线程。
多线程:同一时刻,可以执行多个线程。如一个迅雷进程,可以同时下载多个文件。
并发:由单核CPU实现的多任务同时执行,就是并发。
并行:由多核CPU同时执行多个任务,就是并行。
2. 创建线程的方式
2.1 继承Thread类,重写run方法
package com.javabasic.thread;
/**
* @Description 继承Thread类,创建线程
* @Author yuhuofei
* @Date 2021/8/4
*/
public class ThreadTest{
public static void main(String[] args) {
//新建一个MyThread类的对象,当做一个线程
MyThread myThread = new MyThread();
//启动线程
myThread.start();
}
}
class MyThread extends Thread {
//重写run方法
@Override
public void run() {
System.out.println("启动一个新建的线程");
}
}
2.2 实现Runnable接口,重写run方法
package com.javabasic.thread;
/**
* @Description 通过实现Runnable接口,新建一个线程
* @Author yuhuofei
* @Date 2021/8/4
*/
public class Test {
public static void main(String[] args) {
ThreadImplRunnable threadImplRunnable = new ThreadImplRunnable();
Thread thread = new Thread(threadImplRunnable);
thread.start();
}
}
class ThreadImplRunnable implements Runnable{
@Override
public void run() {
System.out.println("通过实现Runnable接口,新建的一个线程");
}
}
3.线程常用方法
- setName()——设置线程名称
- getName()——获取线程名称
- start()——启动一个线程
- run()——调用线程对象的run方法
- setPriority()——更改线程的优先级
- getPriority()——获取线程的优先级
- sleep()——使当前的线程休眠一定的时间,停止执行,但不会释放锁
- interrupt()——中断线程。一般用于中断正在休眠的线程,使之唤醒
- yield()——线程的礼让。让出CPU,让其它线程执行,但不会释放本线程持有的锁
- join()——线程的插队。抢占执行顺序。
4. 线程的生命周期
从官方的介绍来看,线程的生命周期主要包含六种状态:
- new:新建状态
- runnable:可运行态
- timed_waiting:超时等待状态
- waiting:等待状态
- blocked:阻塞状态
- teminated:终止状态
其中runnable状态,又可细分为ready(就绪)和running(运行)状态,因此如果要细分起来,线程的生命周期应该有七种状态。
线程调用sleep()方法,会使得线程进行timedwaiting超时等待状态,休眠一段时间,这个过程中,线程不会释放锁,直到休眠时间结束,重新进入runnable状态。
线程调用wait()方法,线程进入waiting(等待)状态,这个过程中,会释放锁,直到其它线程通过调用notify()或者是notifyAll()方法将其唤醒。
线程调用同步方法或同步代码块时,遇到锁,在没有获取到锁时,会进入blocked阻塞状态,直到获得锁,才重新进入runnable状态。
第二部分 线程池
1. ThreadPoolExecutor类
ThreadPoolExecutor类是线程池的核心类,它提供了4个构造方法,分别如下:
- 第1个构造方法,包含5个参数
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
- 第2个构造方法,包含6个参数
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
threadFactory, defaultHandler);
}
- 第3个构造方法,包含6个参数
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), handler);
}
- 第4个构造方法,包含7个参数
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
通过观察可以看出,前面的3个构造方法都是在第4个的基础之上演变得到的,所以只要弄清楚第4个,其余3个自然而然也就懂了。
2. 各个参数含义及作用
参数名称 | 参数类型 | 含义 | 作用 |
---|---|---|---|
corePoolSize | int | 核心线程池大小 | 它的线程数量大小决定了添加的任务是开辟新的线程去执行,还是放到workQueue任务队列中去 |
maximumPoolSize | int | 最大线程池大小 | 线程池中的最大线程数量,这个参数会根据你使用的workQueue任务队列的类型,决定线程池会开辟的最大线程数量 |
keepAliveTime | long | 线程存活时间 | 当线程池中空闲线程数量超过corePoolSize时,多余的线程会在多长时间内被销毁 |
unit | TimeUnit | keepAliveTime的单位 | 定下keepAliveTime的单位 |
workQueue | BlockingQueue | 线程等待队列 | 被添加到线程池中,但尚未被执行的任务; 它一般分为直接提交队列(SynchronousQueue)、有界任务队列(ArrayBlockingQueue)、无界任务队列(LinkedBlockingQueue)、优先任务队列(PriorityBlockingQueue) |
threadFactory | ThreadFactory | 线程创建工厂 | 用于创建线程 |
handler | RejectedExecutionHandler | 拒绝策略 | 当任务太多来不及处理时,如何拒绝任务; 自带的拒绝策略有:AbortPolicy策略、CallerRunsPolicy策略、DiscardOledestPolicy策略、DiscardPolicy策略 |
一般来说,如果我们要自定义线程池,重载ThreadPoolExecutor类的构造方法,按自己的需要,更改以上参数即可。
3.JDK自带线程池(Executors类)
JDK自带有5种线程池,存在于Executors类中,如下所示:
- FixedThreadPool
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
- WorkStealingPool
public static ExecutorService newWorkStealingPool(int parallelism) {
return new ForkJoinPool
(parallelism,
ForkJoinPool.defaultForkJoinWorkerThreadFactory,
null, true);
}
- CachedThreadPool
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
- ScheduledThreadPool
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
- SingleThreadExecutor
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
其中WorkStealingPool为JDK1.8新增的线程池。
由于JDK自带的线程池可能会导致OOM(Out Of Memory)或者系统资源耗尽的问题,因此在实际开发中,一般不用JDK自带的线程池,多使用自定义的线程池。