Day288.多线程-面试题汇总 -Juc
Posted 阿昌喜欢吃黄桃
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Day288.多线程-面试题汇总 -Juc相关的知识,希望对你有一定的参考价值。
多线程高频面试题汇总
- 有多少种实现线程的方法?
本质是一种,方式有两种实现Runnable接口&继承Thread类
包装的方式有许多,lambta、线程池
- 实现Runnable接口 和 继承Thread类 哪种方式更好?为什么
实现Runnable接口的方式更好;
- 一个线程两次调用start()方法会怎么样?为什么
会报错,因为start()执行完毕后,线程的生命周期会进入死亡状态,当再次执行,start()方法运行开始他会对线程状态进行检测,那此时这个线程已经处于死亡状态,那就进入不了再启动状态
- 既然start()会调用run()方法,那为什么不直接调用start(),而不是直接调用run()方法
因为start()启动了线程,让现场进入了new的生命周期,而run()方法只是普普通通的一个方法
- 如何正确停止线程
使用interrupt,实现三方配合,一个发起中断,一个检测中断,然后响应中断
- 如何处理不可中断的阻塞
可使用每个类所提供专门的停止线程方法来处理中断等方式
- 线程有几种状态?生命周期是什么?
- 如何用wait()方法实现两个线程交替打印
/******
@author 阿昌
@create 2021-05-23 20:05
*******
* 两个线程交替打印 0 - 100 的奇偶数,用wait和notify
*/
public class WaitNotifyPrintOddEven {
private static int count = 0;
private static final Object lock = new Object();
//主函数
public static void main(String[] args) {
TurningRounder turningRounder = new TurningRounder();
Thread even = new Thread(turningRounder);
Thread odd = new Thread(turningRounder);
even.start();
odd.start();
}
static class TurningRounder implements Runnable {
@Override
public void run() {
while (count <= 100) {
synchronized (lock) {
System.out.println(Thread.currentThread().getName() + "," + count++);
lock.notify();
if (count <= 100) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
}
- 为什么要使用生产者和消费者模式
保证生产消费平衡,通过一个异步的队列来实现
- 什么是生产者消费者模式
生产者生成往queue队列中放,queue队列满了生产阻塞;
消费者消费queue队列,queue队列没了消费阻塞;
生产者生成会向消费者通知消费;
消费者消费会向生成者通知生成
- 手写代码,通过wait/notify实现生产者消费者模式
/******
@author 阿昌
@create 2021-05-22 20:58
*******
* 用wait/notify来实现 生产者消费者模式
*/
public class ProducerConsumerModel {
//主函数
public static void main(String[] args) {
EventStorage eventStorage = new EventStorage();
Consumer1 consumer = new Consumer1(eventStorage);
Producer1 producer = new Producer1(eventStorage);
Thread threadConsumer = new Thread(consumer);
Thread threadProducer = new Thread(producer);
threadConsumer.start();
threadProducer.start();
}
}
//生产者
class Producer1 implements Runnable{
private EventStorage storage;
public Producer1(EventStorage storage) {
this.storage = storage;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
storage.put();
}
}
}
//消费者
class Consumer1 implements Runnable{
private EventStorage storage;
public Consumer1(EventStorage storage) {
this.storage = storage;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
storage.take();
}
}
}
//队列
class EventStorage{
private int maxSize;
private LinkedList storage;
public EventStorage(){
this.maxSize=10;
storage = new LinkedList<>();
}
//生成产品
public synchronized void put(){
//如果满了
while (storage.size()==maxSize){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//如果没满
storage.add(new Date());
System.out.println("生产者生产了产品,仓库里有了"+storage.size()+"个产品");
notify();
}
//消费产品
public synchronized void take(){
//如果空了
while (storage.size()<=0){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//如果没空
System.out.println("消费者消费了产品,拿到了"+storage.poll()+",现在仓库还剩下"+storage.size());
notify();
}
}
- 为什么wait必须在同步代码块中使用
防止在wait之后没有notify唤醒
- 为什么线程通信的wait、notify、notifyAll被定义在object类中,而sleep定义在thread类中
因为在java中每个对象都是一把锁,虽然thread类中也有wait等,但是是不推荐的
- wait方法属于object,那调用wait会怎么样
thread类在运行结束之后自动调用notify,会扰乱我们的逻辑
- 如何选择用notify 还是notifyAll
优先选中notifyAll,除非要求每次只唤醒一个线程,才去使用notify
- notifyAll后所有线程都会再次抢锁,如果某个线程抢夺失败了会怎么样
不会发送错误,而是等待下一次释放锁后再去抢夺
- 用suspend和resume来阻塞线程可以吗?为什么?
不推荐,由于安全问题,方法已经过时
- wait/notify、sleep的异同
wait属于object类,sleep属于thread类;
wait释放锁,sleep不释放锁;
- 在join期间,线程处于什么线程状态
处于waiting状态,他底层就是调用了wait方法
- yield和sleep的区别
- 守护线程和普通线程的区别
区别在于JVM,守护线程服务普通线程,当普通线程数量为0,那么JVM就会被关闭;守护线程不会影响到jvm的结束
- 我们需要给线程设置为守护线程吗
不需要,因为java自带的守护线程足够我们使用
- 为什么程序设计不依赖于线程优先级
因为不同的操作系统对于线程优先级采用的策略都不一样,所以不推荐依赖线程优先级
- 讲一讲Java异常体系
他们继承于Throwable,分为error 和exception;exception下面还分为runtimeexception和非runtimeexception
- 实际工作中,如何全局处理异常
写一个全局异常处理器,来捕获异常
- run方法是否可以抛出异常?如果抛出异常?线程状态会怎么样?
不可以抛出异常,如果抛出,线程就会终止
- 一共有几类线程安全问题
3类
- 那些场景需要额外注意线程安全问题?
资源共享…
- 为什么多线程会带来性能问题
因为切换线程会带来上下文切换,用内存保存上下文环境和加载上下文环境
- Java代码是如何转化,最终被CPU执行
先生成.java文件,然后javac生成字节码文件.class,然后通过jvm读取加载.class文件,生成机器代码,被cpu执行解读
- 单例模式的作用和使用场景
- 单例模式的多种写法、单列和高并发的关系
- 单例各种写法的使用场景
- 饿汉式的缺点
消耗资源,一上来就加载
- 懒汉试的缺点
可能造成线程安全问题
- 为什么要用double-check,不用就不安全吗?
- 为什么双重检查模式要使用volatile
因为构造方法生成对象的过程包含3步骤,不是原子性的,所以会出现可见性和重排序问题
- 最好的单例模式实现是什么?
枚举实现
- 讲一讲什么是java内存模型
- 什么是happens-before
表达可见性问题
- Happens-before的规则
sychronized和lock锁的原则,等等等
- 讲讲volatile关键字
- volatile的使用场景
使用于做触发器;赋值场景
- volatile的作用
直接将线程内存刷入主内存;保证该变量具有可见性和防重排序问题
- volatile和sychronized的异同
volatile是轻量级是sychronized的等。。。。使用的不用场景
- 什么会发生内存可见性问题?
因为cpu是多层缓存结构
- 你知道主内存和本地内存吗?他们是什么
不同的线程拥有自己的本地内存,他们共用一个主内存做为交互通道
- 主内存和本地内存的关系
本地内存之间的交互必须通过主内存;
每一个线程都有自己的本地内存;
- 什么是原子操作
一系列操作要呢全都完成,要呢就完全都不完成
- java中的原子操作有哪些?
除long和double以为的基本数据类型操作。。。。等
- long和double的原子行你了解吗
他们都是64位,在32位的jvm虚拟机中,就需要写入两次,因此就会出现可见性和重排序问题,不是原子操作的原因;一次32位,但是64就不存在这个问题
- 写一个必然死锁的列子
/******
@author 阿昌
@create 2021-05-31 21:16
*******
* 必定发生死锁的情况
*/
public class MustDeadLock implements Runnable {
int flag = 1;//标记位
static Object lock1 = new Object();
static Object lock2 = new Object();
public static void main(String[] args) {
MustDeadLock r1 = new MustDeadLock();
MustDeadLock r2 = new MustDeadLock();
r1.flag=1;
r2.flag=0;
Thread thread1 = new Thread(r1);
Thread thread2 = new Thread(r2);
thread1.start();
thread2.start();
}
@Override
public void run() {
System.out.println("flag= " + flag);
if (flag == 1) {
synchronized (lock1){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock2){
System.out.println(flag);
}
}
}
if (flag == 0) {
synchronized (lock2){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock1){
System.out.println(flag);
}
}
}
}
}
- 生产中什么场景会发生死锁
一个方法获取到多个锁对象
- 发生死锁必然满足的条件是什么
互斥原则;请求与保持条件;不剥夺条件;循环等待条件
- 如何定位死锁的位置
jstack命令;ThreadMXBean
- 如何解决死锁
修复死锁策略;检测与恢复策略;鸵鸟策略
- 实际开发中如何避免死锁
设置超时时间;
多使用并发类;
尽量降低锁的使用粒度;
如果能使用同步代码块,就不使用同步方法;
给你的线程起个有意义的名字;
避免锁嵌套;
分配资源前先看能不能收回;
不要几个功能用同一把锁
- 什么是活跃性问题?活锁、饥饿和死锁有什么区别
让程序一直活跃的运行;
活锁:指的是程序还在消耗资源,但是无法进行推进下去
饥饿:一线程长时间没有获取到资源
以上是关于Day288.多线程-面试题汇总 -Juc的主要内容,如果未能解决你的问题,请参考以下文章