多线程--面试题

总结一下多线程高频面试题。

1.什么是线程?线程和进程的区别?

线程:线程是CPU调度的最小单位,也是程序执行的最小单位。没有单独地址空间,线程属于进程,不能独立执行,每个进程至少要有一个线程,称为主线程。

进程:进程是系统进行资源分配的基本单位,有独立的内存地址空间;

2.描述CPU和多线程的关系

  • 第一阶段,单CPU时代,单CPU在同一时间点,只能执行单一线程。

  • 第二阶段,单CPU多任务阶段,计算机在同一时间点,并行执行多个线程。但这并非真正意义上的同时执行,而是多个任务共享一个CPU,操作系统协调CPU在某个时间点,执行某个线程,因为CPU在线程之间切换比较快,就好像多个任务在同时运行。

  • 第三阶段,多CPU多任务阶段,真正实现的,在同一时间点运行多个线程。具体到哪个线程在哪个CPU执行,这就跟操作系统和CPU本身的设计有关了。

3.什么是线程安全/线程不安全?

线程安全:就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。

线程不安全:就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的数据是脏数据

4.描述下线程的生命周期?

(图很重要,很多公司笔试都会要求画出生命周期图)

img

  • 初始状态 : 线程对象创建完成 就是new创建了一个线程对象

  • 就绪状态 : 线程可以被执行 就是调用了start()方法后的状态

  • 运行状态 : 线程正在运行中 就是就绪状态的线程获取了CPU执行权执行线程

  • 阻塞状态 : 线程休眠 就是调用了Thread.sleep()方法使线程进入休眠

  • 等待队列 : 线程陷入无限的等待中 就是线程执行wait()方法,进入这个状态后

  • 锁池状态 : 线程被唤醒,但没有获取到锁 同步锁被别的线程占用,则该线程放入“锁池”中,进入锁池状态

  • 死亡状态 : 线程执行完毕或被关闭 就是run()方法执行完毕后,线程就进入死亡状态

5.wait、sleep、join、yield的区别

wait:Object类的方法(notify()、notifyAll() 也是Object对象),必须放在循环体和同步代码块中,执行该方法的线程会释放锁,进入线程等待池中等待被再次唤醒(notify随机唤醒,notifyAll全部唤醒,线程结束自动唤醒)即放入锁池中竞争同步锁

sleep:Thread类的方法,必须带一个时间参数。会让当前线程休眠进入阻塞状态并释放CPU(Sleep释放CPU,wait 也会释放cpu,因为cpu资源太宝贵了,只有在线程running的时候,才会获取cpu片段),提供其他线程运行的机会且不考虑优先级,但如果有同步锁则sleep不会释放锁即其他线程无法获得同步锁 可通过调用interrupt()方法来唤醒休眠线程。

yield:让出CPU调度,Thread类的方法, yield()只是使当前线程重新回到就绪状态,所以执行yield()的线程有可能在进入到就绪状态后马上又被执行。调用yield方法只是一个建议,告诉线程调度器我的工作已经做的差不多了,可以让别的相同优先级的线程使用CPU了,没有任何机制保证采纳。

join:一种特殊的wait,当前运行线程调用另一个线程的join方法,当前线程进入阻塞状态直到另一个线程运行结束等待该线程终止。 注意该方法也需要捕捉异常。

6.Synchronized和Lock的区别

  • synchronized关键字主要解决多线程通信时候共享数据同步问题。

  • Synchronized底层使用指令码方式来控制锁的。Lock:底层是CAS乐观锁

  • Synchronized是关键字,内置语言实现,Lock是接口。

  • Synchronized在线程发生异常时会自动释放锁,因此不会发生异常死锁。Lock异常时不会自动释放锁,所以需要在finally中实现释放锁。  

7.ThreadLocal、Volatile、Synchronized 的作用和区别

  1. ThreadLocal不是为了解决多线程访问共享变量,而是为每个线程创建一个单独的变量副本,提供了保持对象的方法和避免参数传递的复杂性。

  2. volatile用volatile修饰的变量,线程在每次使用变量的时候,都会读取变量修改后的最的值。volatile很容易被误用,用来进行原子性操作。

  3. Synchronized 是Java利用锁的机制自动实现的,一般有同步方法和同步代码块两种使用方式。关键字保证了数据读写一致和可见性等问题

    ThreadLocal与Synchronized区别 ThreadLocal和Synchonized都用于解决多线程并发访问,他们两者的区别:

    synchronized是利用锁的机制,使变量或代码块在某一时该只能被一个线程访问,而ThreadLocal为每一个线程都提供了变量的副本,使得每个线程在某一时间访问到的并不是同一个对象,这样就隔离了多个线程对数据的数据共享,而Synchronized却正好相反,它用于在多个线程间通信时能够获得数据共享。一句话来说,Synchronized是为了让多线程进行数据共享,而ThreadLocal为了让多线程进行数据隔离。

8.同步方法和同步块,哪个更好?

同步块是更好的选择,因为它不会锁住整个对象(当然你也可以让它锁住整个对象)。同步方法会锁住整个对象,哪怕这个类中有多个不相关联的同步块,这通常会导致他们停止执行并需要等待获得这个对象上的锁。同步块更要符合开放调用的原则,只在需要锁住的代码块锁住相应的对象,这样从侧面来说也可以避免死锁。

9.什么是死锁?如何避免死锁?

当两个或多个线程同时运行并且拥有对方所需要的资源时,就会等待对方释放所持有的资源,但是都不会释放资源,这样就会造成堵塞,最后形成死锁。 

如何避免线程死锁:

我们只要破坏产生死锁的四个条件中的其中一个就可以了。

破坏互斥条件:这个条件我们没有办法破坏,因为我们用锁本来就是想让他们互斥的(临界资源需要互斥访问)。

破坏请求与保持条件:一次性申请所有的资源。

破坏不剥夺条件:占用部分资源的线程进一步申请其他资源时,如果申请不到,可以主动释放它占有的资源。

破坏循环等待条件:靠按序申请资源来预防。按某一顺序申请资源,释放资源则反序释放。破坏循环等待条件。

10.线程池的作用是什么,常见的参数有哪些?

线程池的作用:

  • 第一:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。

  • 第二:提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。

  • 第三:提高线程的可管理性。

常见参数:

  • corePoolSize:核心线程数

  • queueCapacity:任务队列容量(阻塞队列)

  • maxPoolSize:最大线程数

  • keepAliveTime:线程空闲时间

  • allowCoreThreadTimeout:允许核心线程超时

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

起个名字是真的南

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值