头图

这是我花费时间为大家整理的腾讯面试中常问的多线程面试题,看看你掌握多少?

1.什么是进程?什么是线程?
2.说说线程的生命周期和状态?
3.什么是上下文切换?
4.创建线程创建的方式都有哪些?
5.synchronized 关键字的作用
6.线程池的核心构造参数有哪些?

1. 什么是进程?什么是线程?

什么是进程?

进程是程序的一次执行过程,是系统运行程序的基本单位,因此进程是动态的。
系统运行一个程序即是一个进程从创建,运行到消亡的过程。在 Java 中,当我们启动 main 函数时其实就是启动了一个 JVM 的进程,而 main 函数所在的线程就是这个进程中的一个线程,也称主线程。

下面是进程的特点,帮助大家更好地理解进程

独立性 :进程之间是独立的,互不干扰。一个进程的崩溃不会影响其他进程。
资源丰富 :每个进程拥有独立的资源,包括内存、文件句柄等。
开销大 :创建和销毁进程的开销较大,进程间通信(IPC)也相对复杂。
上下文切换 :进程的上下文切换开销较大,因为需要切换内存空间和资源。
使用场景 :适用于需要强隔离和独立资源的场景,如独立的服务、应用程序等。

什么是线程?

线程与进程相似,但线程是一个比进程更小的执行单位。一个进程在其执行的过程中可以产生多个线程。
与进程不同的是同类的多个线程共享进程的堆和方法区资源,但每个线程有自己的程序计数器、虚拟机栈和本地方法栈,所以系统在产生一个线程,或是在各个线程之间做切换工作时,负担要比进程小得多,也正因为如此,线程也被称为轻量级进程。

下面是线程的特点,帮助大家更好地理解线程

共享资源 :同一进程内的线程共享内存和资源,通信方便。
轻量级 :线程的创建和销毁开销较小,上下文切换较快。
并发执行 :多线程可以并发执行,提高程序的响应速度和资源利用率。
同步问题 :由于共享资源,线程间需要同步机制(如锁)来避免资源竞争和数据不一致。
使用场景 :适用于需要并发执行的任务,如多任务处理、并行计算等。

2. 说说线程的生命周期和状态?

Java 线程在运行的生命周期中的指定时刻只可能处于下面 6 种不同状态的其中一个状态。关于这个知识点,大家记住这 6 个状态,理解每个状态就行

NEW : 初始状态,线程被创建出来但没有被调用 start() 。
RUNNABLE : 运行状态,线程被调用了 start()等待运行的状态。
注意:在 Java 中,Runnable 状态包括了运行状态(Running),即线程可以运行,也可能正在运行。
BLOCKED :阻塞状态,需要等待锁释放。
WAITING :等待状态,表示该线程需要等待其他线程做出一些特定动作(通知或中断)。
TIME_WAITING :超时等待状态,可以在指定的时间后自行返回而不是像 WAITING 那样一直等待。
TERMINATED :终止状态,表示该线程已经运行完毕。线程在生命周期中并不是固定处于某一个状态而是随着代码的执行在不同状态之间切换。

3. 什么是上下文切换?

多线程编程中一般线程的个数都大于 CPU 核心的个数,而一个 CPU 核心在任意时刻只能被一个线程使用,为了让这些线程都能得到有效执行,CPU 采取的策略是为每个线程分配时间片并轮转的形式。
当一个线程的时间片用完的时候就会重新处于就绪状态让给其他线程使用,这个过程就属于一次上下文切换


概括来说就是:当前任务在执行完 CPU 时间片切换到另一个任务之前会先保存自己的状态,以便下次再切换回这个任务时,可以再加载这个任务的状态。任务从保存到再加载的过程就是一次上下文切换。


上下文切换通常是计算密集型的。也就是说,它需要相当可观的处理器时间,在每秒几十上百次的切换中,每次切换都需要纳秒量级的时间。所以,上下文切换对系统来说意味着消耗大量的 CPU 时间,事实上,可能是操作系统中时间消耗最大的操作。

4. 创建线程创建的方式都有哪些?

继承 Thread 类
实现 Runnable 接口
使用 Callable 和 Future 创建线程
基本创建线程的方式大体就是这三种,当然也可以使用线程池创建线程。

下面是演示一下具体怎么创建线程

  1. 继承 Thread 类,重写 run 方法:
public class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + " run()方法正在执行...");
    }
}
  1. 实现 Runnable 接口,实现 run 方法:
public class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + " run()方法执行中...");
    }
}
  1. 实现 Callable 接口,实现 call 方法。通过 FutureTask 创建一个线程,获取到线程执行的返回值:
public class MyCallable implements Callable<Integer> {
    @Override
    public Integer call() {
        System.out.println(Thread.currentThread().getName() + " call()方法执行 中...");
        return 1;
    }
}

5. synchronized 关键字的作用

synchronized 它可以把任意一个非 NULL 的对象当作锁。他属于独占式的悲观锁,同时属于可重入锁。

synchronized 关键字解决的是多个线程之间访问资源的同步性,synchronized 关键字可以保证被它修饰的方法或者代码块在任意时刻只能有一个线程执行。

这是 synchronized 的三种使用方式:

修饰实例方法 :作用于当前对象实例加锁,进入同步代码前要获得当前对象实例的锁
synchronized void method() {
    //业务代码
}
修饰静态方法 :也就是给当前类加锁,会作用于类的所有对象实例,因为静态成员不属于任何一个实例对象,是类成员。
所以如果一个线程 A 调用一个实例对象的非静态 synchronized 方法,而线程 B 需要调用这个实例对象所属类的静态 synchronized 方法,是允许的,不会发生互斥现象,因为访问静态 synchronized 方法占用的锁是当前类的锁,而访问非静态 synchronized 方法占用的锁是当前实例对象锁。
synchronized static void method() {
    //业务代码
}
修饰代码块 : 指定加锁对象,对给定对象加锁,进入同步代码库前要获得给定对象的锁。
synchronized(this) {
    //业务代码
}

6. 线程池的核心构造参数有哪些?

线程池一共 7 个核心构造参数,大家牢记即可。

1.corePoolSize(核心线程数)

线程池中始终保持运行的最小线程数,即使这些线程处于空闲状态也不会被销毁。
当提交一个新任务时,如果当前运行的线程数少于 corePoolSize,即使有空闲线程,也会创建一个新线程来处理任务。

2.maximumPoolSize(最大线程数)

线程池允许创建的最大线程数。当任务队列已满且当前运行的线程数小于 maximumPoolSize 时,会创建新线程来执行任务。

3.keepAliveTime(线程空闲时间)

当线程池中的线程数超过 corePoolSize 时,多余的空闲线程在等待新任务的最大时间。超过这个时间后,这些空闲线程将被终止。

4.unit(时间单位

keepAliveTime 参数的时间单位。可以是 TimeUnit 枚举中的任意值,如TimeUnit.SECONDS、TimeUnit.MILLISECONDS等。

5.workQueue(任务队列)

用于保存等待执行的任务的队列。

常用的队列实现包括:

  • LinkedBlockingQueue:一个基于链表的无界队列。
  • ArrayBlockingQueue:一个基于数组的有界队列。
  • SynchronousQueue:一个不存储元素的队列,每个插入操作必须等待一个对应的移除操作。
  • PriorityBlockingQueue:一个支持优先级排序的无界队列。

6.threadFactory(线程工厂)

用于创建新线程的工厂。可以通过自定义线程工厂来设置线程的名称、优先级等属性。默认实现是Executors.defaultThreadFactory()

7.handler(拒绝策略)

当任务队列已满且线程数量达到最大线程数时,新的任务会被拒绝执行。拒绝策略定义了这种情况下的处理方式。

常用的拒绝策略包括:

  • AbortPolicy:抛出 RejectedExecutionException,默认策略。
  • CallerRunsPolicy:由调用线程执行任务。
  • DiscardPolicy:丢弃任务,不抛出异常。
  • DiscardOldestPolicy:丢弃队列中最旧的任务,然后重新尝试提交新任务。

就业陪跑训练营学员投稿

欢迎关注 ❤

我们搞了一个免费的面试真题共享群,互通有无,一起刷题进步。

没准能让你能刷到自己意向公司的最新面试题呢。

感兴趣的朋友们可以加我微信:wangzhongyang1993,备注:思否面试群。


王中阳讲编程
805 声望297 粉丝