六.JAVA基础面试题:线程
1.什么是线程?什么是进程?进程和线程之间的关系?
2.并行和并发的区别
3.同步和异步的区别
4.为什么要有多线程?多线程产生的问题?
5.线程的生命周期和状态
6.什么是上下文的切换?上下文切换的时机
7.sleep和wait的区别
8.什么是死锁?如何预防死锁
9.Thread类的run方法可以直接使用
1.什么是指令重排序
2.JMM是什么
3.JAVA内存结构和JMM的区别
4.并发编程的三个特性
1.如何禁止指令重排序和保证可见性
2.乐观锁和悲观锁是什么?
3.synchronized是什么?有什么用处?
4.synchronized和volatile的区别
5.ReentrantLock是什么
6.ReentrantLock和sychronized的区别
1.ThreadLoacl有什么用?原理是什么?如何造成内存泄漏的
2.什么是线程池?线程池的好处
3.如何创建线程池
4.Future类的优点
5.FutureTask和Callable的关系
6.AQS的理解
六.JAVA基础面试题:线程
1.什么是线程?什么是进程?进程和线程之间的关系?
- 启动程序后,JVM启动了一个进程,而main函数则启动了一个线程。
- 各个进程相互独立,一个进程可以有多个线程。
- 多个线程之间共享方法区和堆
- 每个线程都有自己的程序计数器,本地方法栈和虚拟机栈(保证程序切换后仍能正确执行,保证线程内容不会被其他线程所破坏)
2.并行和并发的区别
- 并行:两个作业在同一时间段执行
- 并发:两个作业在同一时刻执行
3.同步和异步的区别
- 同步:发出调用后未返回结果则一直等待
- 异步:发出调用后不用等待结果则直接返回
4.为什么要有多线程?多线程产生的问题?
- 互联网的趋势:并发量很大,需要多线程来提高并发能力
- 计算机的发展:多核cpu,一个线程可以用一个cpu
- 多线程带来的问题
内存泄漏
死锁
线程不安全
5.线程的生命周期和状态
- 新建-就绪-运行-死亡
- 运行-阻塞-就绪
6.什么是上下文的切换?上下文切换的时机
- 即JVM保存当前线程的上下文,加载下一个占用cpu的线程上下文
- 上下文切换的时机
主动让出cpu(sleep,wait)
时间片用完
线程被阻塞(io)
线程执行结束
7.sleep和wait的区别
-
sleep用在暂停线程,过了时间即可继续。不会释放锁。用于线程内。Thread类的静态方法。
-
wait用在线程通信,其他线程notify才可继续。会释放锁。用在同步代码块内。Object类的方法。
8.什么是死锁?如何预防死锁
- 多个线程同时被阻塞,且都等待资源的释放,无限阻塞。
- 预防死锁
一次性申请所有资源。
申请不到资源则释放已占有资源。
按顺序获取资源。
9.Thread类的run方法可以直接使用
- Thread类的run方法可以调用但只是普通方法,不会开启线程
- 需要用start来开启线程
1.什么是指令重排序
- 指令重排序
系统执行代码不一定要按照编写代码的顺序执行代码 - 重排序
编译器优化重排(不改变线程的语义)
指令并行重排(流水线并行技术)
内存系统重排 - 产生问题
保证单线程语义一致,但是无法保证多线程语义一致。
2.JMM是什么
- JMM是java内存模型
主要是为了规范并发 - JMM两大结构
主内存:全部线程创建的实例对象都放入主内存中
本地内存:每个线程都有本地内存来存储共享变量的副本,通过主内存和本地内存交互来更新,每个线程只能访问自己的本地内存
3.JAVA内存结构和JMM的区别
- JAVA内存结构是JVM运行时的内存区域
- JMM是规范线程并发的内存关系
4.并发编程的三个特性
- 原子性:要么执行要么都不执行
- 可见性:其他线程要能够立刻看到修改后的变量
- 有序性:指令执行有序
1.如何禁止指令重排序和保证可见性
- 使用volatile关键字(无法保证原子性)
- 使用共享变量时直接导主内存中获取
- 特定的内存屏障禁止指令重排序
2.乐观锁和悲观锁是什么?
- 乐观锁
每次访问不出现问题,只需要提交验证即可。
CAS自旋锁。
可能出现ABA问题,适用于少量读。 - 悲观锁
每次访问都有可能出现问题。
synchronized和ReentrantLock。
一次只能一个线程访问,适用于大量读。
3.synchronized是什么?有什么用处?
- 被它修饰的代码块同一时刻只能有一个线程执行
- 修饰
实例方法(当前对象为锁)
静态方法(当前类的锁)
代码块(指定的锁) - 注意:构造方法不需要使用synchronized修饰,因为构造方法本身就是线程安全的。
4.synchronized和volatile的区别
- volatie,变量,可见性,性能较好
- synchronized,方法和代码块,可见性+原子性
5.ReentrantLock是什么
- 是一个可重入独占式的锁
可重入:线程内部调用线程的锁可以继续获得锁
独占式:其他线程不可读不可写(排他锁)
6.ReentrantLock和sychronized的区别
- 都是可重入的锁
- sychronized 非公平锁(先看是否能获得锁再进入排队队列),自动加锁释放,JVM(操作系统级别)依赖于对象监视器Monitor
- ReentrantLock 公平或非公平锁,手动加锁释放,API级别
1.ThreadLoacl有什么用?原理是什么?如何造成内存泄漏的
- threadlocal可以让每个线程绑定自己的值,即访问变量的每个线程都有自己的本地副本
- 原理
每个线程都有一个ThreadLocalMap,存储以Threadloc为键,以Object为值 - 内存泄漏
垃圾回收机制只清理key而不清理value。
但是ThreadLocalMap的机制有在调用方法时,自动清理所有key为null的记录。
2.什么是线程池?线程池的好处
- 线程池是管理一系列线程的资源地
- 线程池的好处
提高线程的可管理性
降低资源消耗
3.如何创建线程池
- 利用ThreadPoolExecutor为构造函数
- Executor工具类的Executors来创建
4.Future类的优点
- Future是异步思想的运用
5.FutureTask和Callable的关系
- FutureTask 是任务+结果(可以异步获取执行结果)
- FutureTask仅执行一次
- FutureTask本身不能创建线程,需要Thread
- 并且实现了Callable接口的类可以当做参数传入FutureTask开启线程(可以获得结果)
6.AQS的理解
- AQS是抽象队列同步器,是ReentrantLock的核心组件。
- AQS如何实现的
有一个state变量(当被加锁时,则将state从0改成1)
有一个保存线程的变量(当被加锁时,将该变量从null变为加锁的线程)
有一个线程等待队列(如果state值不是0,那么线程进入等待队列) - 实战时
可重入锁:如果判断加锁的是自己,那么可以继续将state从1变到2…3,如果判断加锁的不是自己且state不是0,那么进入等待队列。