多线程面试题

并行和并发有什么区别?

并行:多个线程,一个cpu一件一件处理

并发:多个线程,多个cpu同时运行

线程和进程的区别

一个程序至少1个线程,一个进程至少一个线程,进程在执行过程中拥有独立的内存单元,而多个线程共享内存资源,减少切换次数,从而效率更高,进程是线程的一个实体,是cpu调度和分派的基本单位,势必程序更小的能独立运行的单位,同一个线程之间可以并发执行

创建线程的方式

通过继承Thread类创建线程

  • 创建Thread类的子类,重写run方法。因此把run()方法称为执行体
  • 创建Thread子类的实例,创建了线程对象
  • 调用线程对象的start()接口启动线程

通过Runnable接口创建线程

  • 定义runnable接口的实现类,并重写该接口run()方法
  • 创建Runnable实现类的实例,并一次实例作为Thread的target来创建Thread对象
  • 调用线程对象的start()接口启动线程

通过Callable和Future创建线程

  • 创建Callable接口的实现类,并实现call()方法,具有返回值
  • 创建Callable实现类的实例,使用Future Task类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值
  • 使用FUture Task对象作为Thread对象的target创建并启动新的线程
  • 调用Future Tsk对象的get()ff来获得子类线程执行结束后会有返回值

runnable和callable 的区别

Runnable的run()返回为void,他只是纯粹的执行run()方法中的代码而已

Callable接口中的call()方法是有返回值的,是一个泛型,可以用来获取异步执行的结果

sleep()和wait()方法的区别

sleep()是线程类(Thread)的静态方法,让调用者进入睡眠状态,直到时间结束之后运行,不会释放锁

wait()是Object的方法,可以释放锁,直到被唤醒才运行

创建线程池

固定长度,超过最大数量规模不再变化,线程结束补充新的线程

可缓存的线程池,超过规模回收空闲进程,需求增加自动添加新线程,规模不存在限制

单线程的线程池

创建一个固定长度的线程池,以延时或定时的方法执行任务类似Timer

线程池的状态

Runnin运行、ShutDown关机、Stop停止、Tidying整理、Terminated终止。

Runnin运行:线程池处于运行状态,能够接收新任务,以及对已添加的任务进行处理。

ShutDown关机:

  • 在使用了shotdown()命令之后进入关机状态,
  • 此时线程池不接收新任务,但能处理已添加的任务。

Stop停止:

  • 不接收新任务,不处理已添加的任务,并且会中断正在处理的任务。 
  • 在使用了shoutdownNow()之后进入停止状态

整理:

  • 线程池队列为空,执行中的任务也为空进入整理状态
  • 此时可以执行钩子函数terminated()。terminated()在ThreadPoolExecutor类中是空的,若用户想在线程池变为TIDYING时,进行相应的处理;可以通过重写terminated()函数来实现。

终止:

  • 线程池彻底终止,就变成TERMINATED状态。 
  • Terminated()命令后线程池被彻底终止

submit()和execute() 的区别

接收的参数不同

submit()有返回值,execute()没有

submit()方便异常处理

如何保证多线程的运行安全?

可见性:一个线程对主内存的修改可以被其他线程看到

原子性:同一时刻只有一个线程可以对数据进行操作

有序性:一个线程观察其他现场的指令执行顺序,由于指令重新排序,该结果一般杂乱无序。

多线程锁的升级原理:

无锁——偏向锁——轻量级锁——重量级锁

死锁的四个必要条件

互斥条件:进程对所分配到的资源不允许其他进程进行访问,若其他的进程访问该资源,只能等待,直到占有该资源的进程使用完成之后释放该资源

请求和保持条件:进程获得一定的资源之后,又对其他的资源发出请求,但是该资源可能被其他的进程占有,此时请求阻塞,但又对自己获得的资源保持不变

不可剥夺条件:该线程获取的资源,在未完成使用之前,不可被剥夺,只能在使用完之后自己释放

环路等待条件:是进程发生死锁之后,若干进程之间形成一种头尾相接等待资源的关系

ThreadLocal是什么,有那些使用场景?

线程局部变量是局限于线程内部的变量,属于线程自身所有,不在多个线程间共享。java提供ThreadLocal类来支持线程局部变量。是一种实现线程安全的方式,但是在管理环境下,工作现场的生命周期比任何应用变量的生命周期都要长,任何线程局部变量一旦在工作完成之后没有被释放,java应用就存在内存泄漏的风险

synchronized底层实现原理

synchronized可以保证同一时刻只有一个方法可以进入到临界区,同时他还可以保证共享变量的内存的可见性

可以做用到普通同步方法,静态同步方法,方法同步块

 synchronized 和 volatile 的区别是什么?

volatile本质实在是告诉jvm当前变量在寄存器(工作期间)内的值是不确定的,需要从主存种读取

synchroized是锁定当前变量,只有当前线程可以访问改变量,其他线程被阻塞

volatile仅可在变量种使用

synchronized可以使用在方法,变量,类上

volatile不会造成线程的阻塞,synchronized会造成阻塞

volatile标记的变量不会被编译器优化,synchronized会被编译器优化

synchronized和lock有什么区别?

首先synchronized是内置的关键字,在jvm层面上,Lock是一个类

synchronized无法判断所的状态,lock可以判断

synchronized会自动释放锁,lock不会主动释放锁,需要在finally中释放

synchronized被阻塞,那么剩下的线程就会一直阻塞。lock不一定会一直等下去,如果获得不到锁,线程可能不用一致等待就结束了

synchronized可重入,非公平,lock锁可重入,可判断,可公平

lock适合大量的代码同步问题,synchronized适合少量代码的同步问题

synchronized和ReentranLock的区别是什么

synchronized是关键字,ReentranLock是类更加灵活,可以被继承

ReentranLock可以对获取锁的时间进行设置,避免死锁

ReentranLock可以获取各种锁的信息

ReentranLock可以更灵活的实现多路通知

锁的机制不同ReentranLock底层调用的是Unsafe的park方法加锁

synchronized操作的应该是对象头中的mark word

atomic 的原理

atomic包中的类的基本特性就是在多线程环境下,当有多个线程同时对单个(包括基本类型及引用类型)变量进行操作时,具有排他性,即当多个线程同时对该变量值进行更新时,仅有一个线程能成功,而未成功的线程可以像自旋锁一样继续尝试,直到执行成功

atomic系列的类中的核心方法都会调用unsafe类中的几个本地方法。我们需要先直到一个东西就是Unsafe类,全名为sun.misc.Unsafe,这个类包含了大量的对c代码的操作,包括很多直接内存分配即原子操作的调用,而它之所以是非安全的,是告诉你这个方法的大量操作都存在安全隐患,需要小心使用,否者会有严重的后果。例如在通过unsafe分配内存的时候,如果自己指定某些区域可能会导致一些类似C++一样的指针越界到其他进程的问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值