一、多线程面试

线程的基础知识

线程与进程的区别

愚公移山,移不动,生孩子一起移,就是进程和线程的关系

  • 一个进程可以包含一或多个线程
  • 不同的进程使用不同的内存空间 当前进程下的所有线程可以共享内存空间
  • 线程更轻量

并行和并发的区别


创建线程的方式有哪些

  1. 继承Thread类
  2. 实现Runnable接口
  3. 实现Callable接口(适合有返回值的情况)
  4. 使用线程池:创建一个固定大小的线程池,然后提交任务到线程池中执行

线程包含哪些状态 状态之间是如何变化的

  • 新建
  • 可运行
  • 阻塞 没有抢到锁
  • 等待 调用wait –> 别的线程notify唤醒
  • 时间等待 调用sleep
  • 终结状态

多个线程 如何保证按顺序执行

  • join方法:等待线程运行结束

notify和notifyAll的区别

wait和sleep的区别

放下钥匙出门等待 和 抱着锁睡觉

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

  1. 退出标志
  2. stop方法(作废)
  3. interrupt方法中断
    1. 打断阻塞的线程(sleep、wait、join),线程会抛出InterruptedException异常
    2. 打断正常的线程,可以根据打断状态来标记是否退出线程

线程中并发安全

synchronized关键字的底层原理

采用互斥的方式让同一时刻最多只有一个线程能持有对象锁

底层原理:Monitor

class反汇编之后会有:
monitorenter(上锁)
monitorexit(解锁)
monitorexit(解锁)(finally实现)

关于JMM(java内存模型)

关于CAS(乐观锁) CompareAndSwap

关于volatile (可见性)

  • 可见性:多个线程修改一个变量,其他线程能够看到修改后的值
  • 禁止指令重排序

什么是AQS

AQS的基本工作机制

synchronized和Lock的区别

死锁产生的条件

一个线程需要同时获取多把锁 这时就容易发生死锁

如何进行死锁诊断

使用jdk自带工具

  1. jps:输出jvm中运行的进程状态信息
  2. jstack:查看java进程内线程的堆栈信息

聊一下ConcurrentHashMap(线程安全的HashMap)

  • CAS控制数组节点添加
  • synchronized只所著当前链表或红黑二叉树的首节点 只要hash不冲突 就不会产生并发问题

导致并发程序出现问题的根本原因是什么(java怎么保证多线程的执行安全)

java并发编程三大特称

  • 原子性 (锁)
  • 可见性 (volatile)也可以用锁解决 不过性能不好
  • 有序性 (指令重排)

线程池

说一下线程池的核心参数(线程池的执行原理)

  1. corePoolSize 核心线程数
  2. maximumPoolSize 最大线程数 = (核心线程数+救急线程最大数)
  3. keepAliveTime 生存时间 - 救急线程的生存时间,生存时间内没有新任务,该线程会被释放
  4. unit 时间单位 救急线程的生存时间单位
  5. workQueue 阻塞队列 - 当没有空闲核心线程时 新来任务会加入到这里排队 队列满了会创建救急线程执行任务
  6. threadFactory 线程工厂 - 创建新线程 (设置线程名字 是否是守护线程等)
  7. handler 拒绝策略 - 所有线程都在忙 阻塞队列也满了 会触发拒绝策略

线程池中有哪些常见的阻塞队列

主要用LinkedBlockingQueue

线程池的种类有哪些

为什么不建议使用Executors创建线程池

推荐使用:

使用场景

线程池使用场景