编程知识 cdmana.com

Java多线程部分(基础八股)

实现多线程的方法(3种):

  • 实现Runnable接口
  • 继承Thread类
  • 实现Callable接口

区别:

  • Callable可以有返回值,也可以抛出异常,而runnable并无
  • 继承Thread类需要重写run方法,run方法应该是和线程的创建是解耦的,本方法耦合度高
  • 继承Thread类来实现,每次新建一个任务,只能去新建一个独立的线程,新建一个独立的线程,损耗是比较大的。而Runnable 可以利用线程池等工具,减少了创建线程和销毁线程的损耗
  • Java不支持双继承,继承了Thread类以后导致该类无法继承其他类

一个线程两次调用start()方法会怎样?

会报线程状态异常。原因是:start方法启动时会先检查线程状态

start方法的含义:

(1)启动新线程,通知jvm在空闲时启动新线程
(2)主线程调用

start方法的启动过程:

  • 启动新线程检查线程状态
  • 加入线程组
  • 调用start0()

如何正确的停止线程?

  • 使用interrupt来请求停止线程
  • 使用interrupt是用来通知线程停止,并不是强制
  • 想要停止线程,需要请求方、被停止方、子方法被调用方相互配合
  • 使用volatile设置boolean标记位:Volatile 出现线程阻塞时,不能即时更新,故并不可取
  • 用stop停止线程,会导致线程运行到一半突然停止,没有办法完成一个基本单位的操作,造成脏数据(已被弃用)
  • suspend:会使线程挂起,但并不会释放自身的锁,容易造成死锁(已被弃用)

注意:在while中使用try/catch,会导致中断失败

如何处理不可中断的阻塞?

首先,对于本方法没有统一的方法。
我们通常可以:继承thread类 重写原来中断线程或者取消任务的方法,在方法里面加入自己的取消操作,比如关闭数据流,关闭套接字等,然后再调用父类的中断方法,这样就可以既关闭了阻塞的任务,又中断了线程。

线程的生命状态:

引用慕课网悟空老师的图

为什么wait()需要在同步代码块中使用,而sleep()不需要?

为了使通信变得可靠,防止死锁或者永久等待的发生,wait()需要线程间相互配合

wait和sleep方法的异同

  • 相同点:
    wait和sleep方法都可以使线程阻塞,对应的线程状态是 Waiting或Time_Waiting
    wait和sleep方法都可以响应中断 Thread.interrupt

  • 不同点:
    wait方法必须在同步代码块中执行,而sleep则不需要
    在同步方法里执行sleep时,不会释放monitor锁,但是wait方法会释放
    sleep方法短暂休眠后会主动退出阻塞,而wait方法则需要被其他线程唤醒
    wait()和notify(),notifyAll()是Object类的方法,sleep()和yield()是Thread类的方法

为什么wait.notify和notifyAll被定义在Object类里,而sleep定义在Thread类里?

Wait()等方法是一个锁级别的操作,锁是属于某一个对象的。(每一个对象在对象头中都有几位用来保存当前锁的状态)锁是绑定在某一个对象中,而并不是线程中。定义在Thread后,不能实现一个线程多个锁的状态

join方法

  • 作用:主线程等待子线程执行
  • 在join期间,线程是Waiting状态

yield方法

  • 作用:释放该线程的CPU时间片
  • 释放后的线程是Runnable状态

守护线程和普通线程的区别

  • 整体无区别
  • 用户线程会影响JVM的退出 守护线程不会
  • 用户线程是执行开发者的逻辑的,守护线程是服务于我们的

是否需要认为的给线程设置守护线程:

不应该将用户线程设为守护线程,会导致数据不一致,程序强行终止等谜之错误

run方法是否可以抛出异常

run方法不能自己向外抛出,只能自己使用try/catch抛出 线程会终止运行打出进程堆栈。状态为Waiting
在这里插入图片描述
解决逸出的两种方法:

  • 返回”副本“
  • 工厂模式:将构造函数完整执行之后,再将对象交给外界访问

在这里插入图片描述

为什么多线程会带来性能问题?

在这里插入图片描述

版权声明
本文为[ordinaryBlog]所创,转载请带上原文链接,感谢
https://blog.csdn.net/kang2411212/article/details/119830880

Scroll to Top