Day280.线程8大基础知识---面试题总结 -Juc
Posted 阿昌喜欢吃黄桃
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Day280.线程8大基础知识---面试题总结 -Juc相关的知识,希望对你有一定的参考价值。
线程8大基础知识—面试题总结
1、有多少种实现线程的方法?
2种,但本质只有1种;继承Thread类、实现Runnable接口。他们的实现线程方式无非都是通过这两种方式实现
2、实现Runnable接口和继承Thread类哪种方式好?
实现Runnable接口的方式要好
- 节省资源
- 解耦,run()方法跟线程继承应该是分开的
- 接口可被多实现
3、一个线程两次调用start()方法会出现什么情况?为什么?
会报错,因为每个线程运行就一次结束后,他的生命周期就结束了,关闭线程后他会将线程设置为关闭状态;
如果还想要运行,就只能重新建一个线程,再执行start()方法。
4、既然start()会调用run()方法,那为什么不直接调用run()方法呢?
因为调用start()会启用线程,run()只是一个普通方法
5、如何停止线程
通过interrupt中断的方式停止线程,并且要求在里面有进行中断响应判断,相互配合才可以正确关闭;
不推荐使用stop()…等已经被弃用的方法
6、如何处理不可中断的阻塞
没有一个套路,需要根据不同情况,进行不同的处理;如果没有办法处理,那就让他苏醒后让他更快的感受到这次的中断
7、线程有哪几种状态?生命周期是什么?
New新建线程;Runnable已启动线程;Blocked阻塞线程;Waiting等待线程;TimeWaiting时间等待线程;Terminated终止线程
8、用程序实现两种线程交替打印0-100的奇偶数
/******
@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();
}
}
}
}
}
}
}
9、手写生产者消费者设计模式
/******
@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()需要在同步代码块内使用,而sleep()不需要
防范线程等待问题,wait()会释放锁,而sleep不释放锁
十一、为什么线程通信的方法wait(),notify和notifyAll()被定义在Object类里?二sleep()定义在Thread类中?
因为Java每个对象都作为一个锁的单位
十二、wait方法是Object对象的,那在Thread.wait调用会怎么样?
Thread类执行完毕后会自动对 线程对象 执行notify()
十三、notify和notifyAll的区别
notify:随机唤醒一个阻塞状态的线程
notifyAll:唤醒全部阻塞状态线程
十四、notifyAll之后所有的线程都会再次抢夺锁,如果某线程抢夺失败会怎么样?
在入口级再等待下次锁对象被释放,再去抢夺锁
十五、suspend()和resume()来阻塞线程可以吗?为什么?
可以的,会有数据风险问题
十六、wait/notify、sleep异同(方法属于哪个对象?线程状态怎么切换)
前者属于Object类;后者属于Thread类;前着释放锁,后者不释放锁;
他们都会使线程进入阻塞状态
十七、在join期间线程处于哪种状态?
处于waiting状态
join方法里面底层其实就是调用wait方法,并通过Thread类底层调用notify唤All醒
十八、守护线程和普通线程的区别
守护线程服务于普通线程,当普通线程全部被关闭后JVM也会关闭,但是守护线程没有被关闭完,JVM也会关闭
十九、我们是否需要给线程设置为守护线程?
不需要,因为Java所提供的守护线程足够使用
二十、run方法是否可以抛出异常,如果抛出异常,线程状态会怎么样?
二十一、线程中如何处理某个未处理异常?
通过实现UnCaughtExceptionHanlder来捕获这个异常
二十二、什么是多线程的上下文切换?
上下文就是线程运行执行的进度环境,切换就是当他被阻塞切换为其他线程执行后,要保存这个环境和进度所消耗的资源
以上是关于Day280.线程8大基础知识---面试题总结 -Juc的主要内容,如果未能解决你的问题,请参考以下文章
Java核心面试宝典Day14“线程池”高频面试题总结!✊✊✊
Java核心面试宝典Day14“线程池”高频面试题总结!✊✊✊
Java核心面试宝典Day12“Java虚拟机”相关面试题大总结