1 Star 1 Fork 0

浪迹 / MySQL

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
面试题复习.md 10.81 KB
一键复制 编辑 原始数据 按行查看 历史
浪迹 提交于 2021-04-08 17:45 . update 面试题复习.md.

线程和线程池相关的

1.线程的生命周期

1.线程的生命周期总共有五步

新建 ,就绪,运行,助塞,死亡

新建:用new 关键字建立一个线程后,该线程就处于新生状态。处于新生状态的线程有自己的内存空间,通过调用start() 进入就绪状态。

就绪:处于就绪状态线程具备运行条件,但还没分配到CPU,处于就绪队列,等待系统为其分配CPU。当系统选定一个等待线程执行后,它就会从就绪状态进入到运行状态,这个动作称为“CPU调度” 。

运行: 在运行状态的线程执行了自己的run方法里面的代码,直到等待某资源阻塞或者完全完成而死亡。如果在给定的时间段没有执行结束,就会被系统换下来 回到就绪状态。

阻塞:处于运行状态下的线程在某些情况下,如执行了sleep(睡眠),wait()方法,或等待I/O设备等资源,将让出CPU暂时停止自己的运行,进入阻塞状态。

​ 在阻塞状态的线程是不能进入就绪队列的。只有到引起阻塞的原因消除时,或等待的I/O设备空闲下来,线程便转入就绪状态,重新到就绪列中排队等待,被系统选中后从原来停止的位置开始继续执行。

死亡:死亡状态是生命周期的最后一个阶段。线程死亡的原因有三个,一个是正常运行得线程完成了它的全部工作;另一个就是被强制的终止,如通过stop的方法来终止一个线程(不被推荐);三是线程抛出未被捕捉的异常。

img

2.线程进入阻塞的原因有哪些

​ 1.等待I/O的输入输出。

​ 2.等待网络资源,即网速问题。

​ 3.调用sleep方法,要等待sleep方法时间结束。

​ 4.调用了wait方法,需要调用notify唤醒线程。

​ 5.其他线程执行了join方法,当前线程则会阻塞,需要等其他线程执行完成。

3.线程进入死亡状态的原因

​ 1.线程正常完成工作。

​ 2.调用了stop方法,强行停止了线程。

​ 3.外部原因中断线程。

2.进程和线程的区别

1.何为进程

进程是程序的一次执行过程,是系统运行程序的基本单位,因此进程是动态的。系统运行一个程序即是一个进程从创建,运行到死亡的一个过程。

在Java中,当我们启动main 函数时其实就是启动了一个JVM进程,而main函数所在的线程就是这个进程中的一个线程,也称主线程。

2.何为线程

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

3.进程和线程的区别

​ 1.一个进程中可以有多个线程,线程是进程划分成的最小运行单位。

​ 2.多个线程共享的堆和方法区资源,但是每个线程都有自己的程序计数器,虚拟机栈和本地方法栈。

​ 3.线程和进程最大的不同在于基本上各进程的独立的,而个线程则不一定,因为同一进程中的线程级有可能会相互影响。线程执行开销小,但不利于资源的管理和保护;而进程相反。

3.多线程创建方式和各自的特点

1.继承Thread类

2.实现Runnable接口的run方法,并把Runnable实例专给Thread类

3.实现Callable接口

  1. Java不支持双继承,继承了Thread类限制了可扩展性。

  2. 继承Thread类相对于实现Runnable 接口,每次新建一个任务只去新建一个独立的线程,执行完了又要去销毁,如果使用Runnable接口可以利用线程池之类的工具可以减少这些创建线程和销毁线程带来的损耗。

  3. Runnable接口不会返回结果或抛出异常,但是Callable的返回值可以通过Future Task进行封装。

4. start()和run()的关系

  1. Thread类也是实现了Runnable接口,而 Runnable接口 定义了唯一一个run方法,所以基于Thread和Runnable创建的多线程多需要实现run方法,是多线程真正运行方法体。

  2. start方法则是Thread类的方法,用来启动一个线程,然后主线程立刻返回。该启动的线程不会马上运行,会放到等待队列中等待CPU调度,只有线程真正的被CPU调度时才会调用run方法。

  3. 所以start的方法就是标识线程为就绪状态的一个附加方法,start方法被标识为Synchronized的,即为了防止被多次启动的一个同步操作。

  4. 如果直接调用run的方法,那就等于调用了一个普通方法,达不到多线程的异步执行。

5. sleep()和wait()的区别

1.声明类不同,sleep()是Thread类下的,wait()是Object类下的。

  1. sleep方法不会释放锁,wait方法释放锁。

  2. sleep通常被用于暂停执行,wait通常被用于线程间通信。

  3. sleep执行完后线程会自动苏醒,wait则不会,需要调用notify或者notifyAll方法,或者使用wait(long timeout)超时后线程会自动苏醒。

  4. sleep 可以随便随地的使用,但wait只能在synchronized方法中,或者synchronized代码块中使用。

6.什么说线程池(thread pool)

在面向对象线程中,创建和销毁对象是很费时间的,因为创建一个对象要获取内存资源或者其他更多资源。

在Java 中更是如此,虚拟机将试图跟踪每一个对象,以便能过在对象销毁后进行垃圾回收。所以提高服务程序效率一个手段就是尽可能减少创建和销毁对象次数,以便能够在对象销毁后进行垃圾回收,这就是池化资源技术的产生的原因。线程池顾名思义就是事先创建若干个可执行的线程放入一个池(容器)中,需要的时候从线程池中 获取线程不用自行创建,使用完毕后不需要销毁线程而是放入池中,从而减少创建与销毁线程对象的开销。

7.一个线程池包括以下四个基本组成部分;

1.线程池管理器(ThreadPool):用于创建并管理线程池,包括创建线程池,销毁线程池,添加新任务;

2.工作线程(PoolWorker):线程池中线程,在没有任务时处于等待状态,可以循环的执行任务;

3.任务接口(Task):每个任务必须实现的接口,以供工作线程调度任务的执行,它主要规定了任务的入口,任务执行完后的收尾工作,任务的执行状态等;

4.任务队列(taskQueue):用于存放没有处理的任务。提供一种缓存机制。

8.线程池的优点

1.重用存在的线程,减少对象创建销毁的开销。

2.可有效控制最大的并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞。

3.提供定时执行,定期执行,单线程,并发数控制得功能。

9.创建的线程池

  1. newSingleThreadExecutor :单线程的线程池,即线程池中每次只有一个线程工作,单线程串行执行任务。
  2. newFixedThreadExecutor:固定数量线程池,没有提交一个任务就是线程,直到达到线程池最大数量,然后后面进入等待队列直到前面的任务完成才继续执行。
  3. newCacheThreadExecutor:可缓存线程池,当线程池大小超过了处理任务所需的线程,那么会回收部分空间的线程,当有任务来时,又智能的添加新线程来执行。
  4. newScheduleThreadExecutor:大小无限制的线程池,支持时间和周期的执行线程。

10.线程池常用参数

  1. corePoolSize :核心线程池的大小

  2. maxPoolSize:最大可创建的线程数

    3.queueCapacity:队列最大长度

  3. keepAliveSeconds 线程池维护线程所允许的空闲时间

11.线程池状态

  1. 运行状态(RUNNING):线程池一般被创建就处于running状态,任务数为0,能够接收新任务,对已排队的任务进行处理。

​ 2.待关闭状态(SHUTDOWN):不接收新任务,但能处理已排队的任务。调用线程池shutdown()方法,线程池由running转变为SHUTDOWN状态。

​ 3.停止状态(STOP):不接收新任务,不处理已排队的任务,并且会中断正在处理的任务。调用线程池的shutdown()方法,线程池由(RUNNING或SHUTDOWN)转变STOP状态。

​ 4.整理状态(TIDYING): SHUTDOWN 状态下,任务数为0,其他所有任务已终止,线程池会变为TIDYING状态,会执行terminated() 方法。

​ 线程池在SHUTDOWN状态,任务队列为空且执行中任务为空,线程池就会由SHUTDOWN 转变为TIDYING状态。

​ 线程池在STOP 状态,线程池中执行中任务为空时,会由STOP转变为TIDYING状态。

​ 5.终止状态(TERMINATED):线程池彻底终止。线程池在TIDYING状态执行完terminated()方法就会由TIDYING转变为TERMINATED状态。

    private static final int RUNNING    = -1 << COUNT_BITS;
    private static final int SHUTDOWN   =  0 << COUNT_BITS;
    private static final int STOP       =  1 << COUNT_BITS;
    private static final int TIDYING    =  2 << COUNT_BITS;
    private static final int TERMINATED =  3 << COUNT_BITS;

12.什么时候会饱和?

1.当核心线程corePoolSize满且阻塞队列也满时才会判断当前线程数是否小于最大线程数,并决定是否创建新线程,如果创建的线程总数大于maximumPoolSize的时候,就会触发RejectedExecetionHandler。

2.饱和策略有哪些?

JDK主要提供了4种饱和策略供选择。4种策略都做为静态内部类在ThreadPoolExcutor中进行实现。

AbortPolicy中止策略、DiscardPolicy抛弃策略、DiscardOldestPolicy抛弃旧任务策略、CallerRunsPolicy调用者运行

ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。 ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。 ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程) ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务

3.JUC封装的4种线程池

newCachedThreadPool、newFixedThreadPool、newScheduledThreadPool、newSingleThreadExecutor

SQL
1
https://gitee.com/langren19/my-sql.git
git@gitee.com:langren19/my-sql.git
langren19
my-sql
MySQL
master

搜索帮助

53164aa7 5694891 3bd8fe86 5694891