【Java面试丨并发编程】线程的基础知识

一、进程与线程的区别

1. 进程

  • 程序是由指令和数据组成,但这些指令要运行,数据要读写,就必须将指令加载至CPU,数据加载至内存
  • 在指令运行过程中还需要用到磁盘、网络等设备
  • 进程就是用来加载指令、管理内存、管理IO的
  • 当一个程序被运行,从磁盘加载这个程序的代码至内存,这时就开启了一个进程
    【Java面试丨并发编程】线程的基础知识_第1张图片

2. 线程

  • 一个线程就是一个指令流,将指令流中的一条条指令以一定的顺序交给CPU执行
  • 一个进程之内可以分为一到多个线程
    【Java面试丨并发编程】线程的基础知识_第2张图片

3. 二者区别

  • 进程是正在运行程序的实例,进程中包含了线程,每个线程执行不同的任务
  • 不同的进程使用不同的内存空间,在当前进程下的所有线程可以共享内存空间
  • 线程更轻量,线程上下文切换成本一般要比进程上下文切换低(上下文切换:指从一个线程切换到另一个线程)

二、并行与并发的区别

1. 单核CPU

  • 单核CPU下线程实际是串行执行的
  • 操作系统中有一个组件为任务调度器,其将CPU的时间片(Windows下时间片最小约为15毫秒)分给不同的程序使用,由于CPU在线程之间的切换非常快,人类感觉是同时运行的
  • 总结:微观串行,宏观并行
  • 一般会将这种线程轮流使用CPU的做法称为并发(Concurrent)
    【Java面试丨并发编程】线程的基础知识_第3张图片

2. 多核CPU

  • 每个核(Core)都可以调度运行线程,这时候线程可以是并行的
    【Java面试丨并发编程】线程的基础知识_第4张图片

3. 二者区别

  • 现在都是多核CPU,在多核CPU下
    (1)并发(Concurrent):同一时间应对(dealing with)多件事情的能力,多个线程轮流使用一个或多个CPU
    (2)并行(Parallel):同一时间动手(doing)多件事情的能力,4核CPU同时执行4个线程
    【Java面试丨并发编程】线程的基础知识_第5张图片

三、线程创建的方式有哪些

1. 继承Thread类

【Java面试丨并发编程】线程的基础知识_第6张图片

2. 实现Runnable接口

【Java面试丨并发编程】线程的基础知识_第7张图片

3. 实现Callable接口

【Java面试丨并发编程】线程的基础知识_第8张图片

4.线程池创建线程【项目中推荐使用该方式】

【Java面试丨并发编程】线程的基础知识_第9张图片

四、Runnable和Callable接口有什么区别

  • Runnable接口的run()方法没有返回值
  • Callable接口的call()方法有返回值,是个泛型,和Future、FutureTask配合可以用来获取异步执行的结果
  • Callable接口的call()方法允许抛出异常;而Runnable接口的run()方法的异常只能在内部消化,不能继续上抛

五、线程包括哪些状态,状态之间是如何变化的

1. 线程的状态

  • 可以参考JDK中Thread类中的枚举类State
    【Java面试丨并发编程】线程的基础知识_第10张图片

2. 状态之间转换

  • 创建线程对象是新建状态
  • 调用了start()方法转变为可执行状态
  • 线程获取到了CPU的执行权,执行结束是终止状态
  • 在可执行状态的过程中,如果没有获取到CPU的执行权,可能会切换成其他状态
    (1)如果没有获取到锁(Synchronized或Lock),则进入阻塞状态;获得锁再切换为可执行状态
    (2)如果线程调用了wait()方法,则进入等待状态,其他线程调用notify()方法唤醒后可切换为可执行状态
    (3)如果线程调用了sleep()方法,则进入计时等待状态,到时间后可切换为可执行状态
    【Java面试丨并发编程】线程的基础知识_第11张图片

六、在Java中wait()和sleep()方法的不同

1. 共同点

  • wait()/wait(long)和sleep(long)方法:效果都是让当前线程暂时放弃CPU的使用权,进入阻塞状态

2. 不同点

  • 方法归属不同
    (1)wait()/wait(long)方法:Object类的成员方法,每个对象都有
    (2)sleep(long)方法:Thread类的静态方法
  • 醒来时机不同
    (1)wait()/wait(long)方法可以被notify()/notifyAll()方法唤醒,wait()方法如果不被唤醒则一直等下去
    (2)执行wait(long)和sleep(long)方法的线程都会在等待相应毫秒后醒来
    (3)它们都可以被打断唤醒
  • 锁特性不同(重点)
    (1)wait()/wait(long)方法的调用必须先获取对象的锁,而sleep(long)方法无此限制
    (2)wait()/wait(long)方法执行后会释放对象锁,允许其他线程获得该对象锁(释放锁,在睡觉)
    (3)sleep(long)方法如果在Synchronized代码块中执行,并不会释放对象锁(抱着锁,在睡觉)

七、新建三个线程T1、T2、T3,如何保证它们按顺序执行

1. join()方法

  • join()方法:等待线程运行结束
  • t.join():阻塞调用此方法的线程,进入timed_waiting,知道线程t执行完成后,此线程再继续执行
    【Java面试丨并发编程】线程的基础知识_第12张图片

八、notify()和notifyAll()方法有什么区别

  • notify()方法:只随机唤醒一个wait线程
  • notifyAll()方法:唤醒所有wait线程

九、线程的run()和start()方法有什么区别

  • start()方法:用来启动线程,通过该线程调用run()方法执行run()方法中所定义的逻辑代码。start()方法只能被调用一次
  • run()方法:封装了要被线程执行的代码,就是一个普通的方法,可以被调用多次

十、如何停止一个正在运行的线程

  • 使用退出标志,使线程正常退出,也就是当run()方法完成后线程终止
  • 使用stop()方法强制终止(不推荐,该方法已作废)
  • 使用interrupt()方法中断线程
    (1)打断阻塞的线程(sleep、wait、join),线程会抛出InterruptedException异常
    (2)打断正常的线程,可以根据打断状态来标记是否退出线程

你可能感兴趣的:(Java面试,java,面试)