当前位置: 首页 > news >正文

【并发编程】线程基础知识

线程基础知识

1. 线程与进程的区别

在这里插入图片描述

  • 进程是正在运行程序的实例,进程中包含了线程,每个线程执行不同的任务;
  • 不同的进程使用不同的内存空间,在当前进程下的所有线程可以共享内存空间;
  • 线程更加轻量,线程上下文切换成本一般要比进程上下文切换低(上下文切换指的是一个线程/进程暂停,切换到另一个线程/进程执行,保存上一个线程/进程的上下文,加载下一个线程/进程的上下文);
    • 上下文指的是一些执行的环境,状态,场景值;

2. 并行与并发的区别

在多核 CPU 下:

并发就是同一段时间,某个 CPU 内核轮流地(“同时”)执行多件事情;

在这里插入图片描述

在这里插入图片描述

并行就是同一时间点,多个 CPU 内核真的同时执行了多件事情,例如四核 CPU 就可以同时执行 4 个线程;

  • 单核就没有并行了,只能说从宏观来看是并行;

3. 创建线程的方式有哪些?

  1. 重写 Thread 的 run 方法;
    1. 子类继承 Thread;
    2. 匿名内部类;
  2. 实现 Runnable 函数式接口的 run 方法;
    1. 子类实现 Runnable,传参给 Thread 的构造方法;
    2. 匿名内部类;
    3. lambda 表达式;
  3. 实现 Callable 函数式接口的 call 方法;
    1. 子类实现 Callable,传参给 FutureTask 的构造方法,FutureTask 是 Runnable 的实现类,传参给 Thread 的构造方法;
    2. 匿名内部类;
    3. lambda 表达式;
  4. 线程池创建线程(该线程不会轻易结束,可以反复用于执行任务队列的任务);
    • 线程池可以通过工厂类 Executors 去构造,如 newFixedThreadPool,固定线程池线程数的生产方法;
    • 提交 Runnable、Callable 实现类/匿名内部类/lambda 表达式到线程池 ExecutorService;

4. Runnable 和 Callable 有什么区别?

  • Runnable 的 run 方法没有返回值;
  • Callable 的 call 方法有返回值,通过 FutureTask 对象获取结果;
  • Callable 接口的 call 方法允许 throws 异常,但是 Runnable 接口的 run 方法不允许
    • 因为在接口声明方法的时候,Callable 的接口方法有 throws,而 Runnable 没有;
    • 所以 Callable 接口方法的实现方法自然就可以 throws 也可以不 throws,Runnable 则不能 throws;

5. run 方法 和 start 方法有什么区别?

  • start 方法是用来启动线程的,通过该线程调用 run 方法执行 run 方法中所定义的逻辑;
    • 一个线程 start 只能执行一次;
  • run 方法则只是封装了业务逻辑的代码,是要被线程执行的;
    • 就是个普通的 Java 方法,当然也就可以多次调用;

6. 线程包括哪些状态?状态之间是如何变化的?

在这里插入图片描述

回答:

  • 线程状态包括:
    1. 未启动的**“新建”状态**(NEW);
    2. 可执行的**“就绪”/“运行”状态**(RUNNABLE);
    3. 没有获得锁的**“阻塞”状态**(BLOCKED);
    4. 调用 wait 方法的**“等待”状态**(WAITING);
    5. 调用 sleep 方法的**“计时等待”状态**(TIMED_WAITING);
    6. 线程执行结束后的**“终止”状态**(TERMINATED);

补充:

对于join方法,如果有时间限制就是 TIMED_WAITING,否则是 WAITING

在这里插入图片描述

回答:

  1. 创建线程对象时,是新建状态
  2. 调用了 start 后,是可执行状态
  3. 参与锁竞争,没有获得锁,是阻塞状态,获得锁则变回可执行状态
  4. 调用 wait 方法,是等待状态,被其他线程调用 notify 唤醒后,变回可执行状态
  5. 调用 sleep 方法,是计时等待状态,时间一到,变回可执行状态
  6. 执行完成,是终止状态

可执行状态,跟有无 CPU 执行无关,因为 CPU 调度是无序的,如果没有锁、wait、sleep、join 限制,“有无 CPU 执行”几乎是同时;

7. 新建 T1、T2、T3 三个线程,如何保证它们顺序执行?

在这里插入图片描述

当然,也可以用 wait 与 notify;

8. notify 与 notifyAll 的区别?

synchronized(obj) {obj.notifyAll();
}
  • notifyAll:唤醒 wait 这把锁的所有线程参与锁竞争;
synchronized(obj) {obj.notify();
}
  • notify:唤醒 wait 这把锁的随机一个线程参与锁竞争;

如果 synchronized 代码块还没有结束,那么 notify/notifyAll 的线程会继续参与锁竞争;

9. wait 和 sleep 的区别?

共同点:

  • wait()、wait(long)、sleep(long) 的效果都是让当前线程暂时放弃 CPU 的使用权,进入阻塞状态;

不同点:

  1. 方法归属不同:
    • sleep(long) 是 Thread 的静态方法;
    • 而 wait 方法都是 Object 的成员方法,任何对象都能调用;
  2. 醒来的时机不同:
    • sleep(long) 会在相应毫秒后醒来;
    • wait 方法则需要被 notify 唤醒,而如果不唤醒 wait() 会一直等下去,wait(long) 会在相应毫秒后醒来;
    • 但是它们都可以被打断而被唤醒;
  3. 锁特性不同:
    • sleep 方法如果获得锁后执行,不会释放锁
      • (放弃 CPU,我睡一会儿,期间你们也用不了);
      • 但是 sleep 方法不需要获得锁就能执行;
    • wait 方法则必须在获得锁的前提下,主动释放锁,并且没到时间/没被唤醒,不会参与锁竞争
    • (我放弃 CPU,但是你们还可以用);

10. 如何停止一个正在运行的线程?

有三种方式可以停止线程:

  1. 退出标志法,使用一个能够被线程 run 方法获取到的布尔类型变量,当别的线程将其设置为 true 时,则线程结束;

    • 当然,这里更加体现的是,程序员自定义去安装某个规则/条件去中断线程;
  2. 使用 stop 方法强制终止(不推荐)

  3. 使用 interrupt 方法中断线程:

    1. 打断正常的线程,可以通过 isInterrupted() 方法来判断是否被要求中断,由程序员决定做什么收尾;
    2. 打断阻塞(sleep、wait、join、等待锁释放)的线程,线程抛出 InterruptedException 异常,当然,你处理异常后仍然可以用 isInterrupted() 方法来判断是否被要求中断,由程序员决定做什么收尾;

    不要不按套路出牌,isInterrupted() 方法为 true ,正确的做法就是收尾了,而不是置之不理,这样 interrupt 方法就没有意义了;

相关文章:

  • 我是如何写作的?
  • 深入理解分库、分表、分库分表
  • C#学习总结
  • 大数据技术(一)
  • Visual Studio C++项目远程断点调试客户现场程序方法
  • 蓝桥杯(3.1)
  • 李沐动手学习深度学习——4.2练习
  • 面试数据库篇(mysql)- 06覆盖索引
  • 一句话讲清楚数据库中事务的隔离级别(通俗易懂版)
  • 贪心 Leetcode 53 最大子数组和
  • Pycharm的下载安装与汉化
  • 【Mybatis】多表映射 第二期
  • 德人合科技 | 天锐绿盾终端安全管理系统
  • GO数组切片
  • 排序算法--堆排序
  • Google 是如何开发 Web 框架的
  • 分享的文章《人生如棋》
  • codis proxy处理流程
  • C语言笔记(第一章:C语言编程)
  • Docker 笔记(1):介绍、镜像、容器及其基本操作
  • Java编程基础24——递归练习
  • Linux CTF 逆向入门
  • miniui datagrid 的客户端分页解决方案 - CS结合
  • opencv python Meanshift 和 Camshift
  • Spark RDD学习: aggregate函数
  • swift基础之_对象 实例方法 对象方法。
  • 闭包--闭包之tab栏切换(四)
  • 互联网大裁员:Java程序员失工作,焉知不能进ali?
  • 来,膜拜下android roadmap,强大的执行力
  • 适配iPhoneX、iPhoneXs、iPhoneXs Max、iPhoneXr 屏幕尺寸及安全区域
  • 通信类
  • 新版博客前端前瞻
  • elasticsearch-head插件安装
  • "无招胜有招"nbsp;史上最全的互…
  • # 数据结构
  • #1015 : KMP算法
  • #我与Java虚拟机的故事#连载17:我的Java技术水平有了一个本质的提升
  • ${ }的特别功能
  • (二)学习JVM —— 垃圾回收机制
  • (附源码)ssm航空客运订票系统 毕业设计 141612
  • (六)什么是Vite——热更新时vite、webpack做了什么
  • (删)Java线程同步实现一:synchronzied和wait()/notify()
  • (十)c52学习之旅-定时器实验
  • (一)python发送HTTP 请求的两种方式(get和post )
  • (转)详解PHP处理密码的几种方式
  • (轉貼) VS2005 快捷键 (初級) (.NET) (Visual Studio)
  • *1 计算机基础和操作系统基础及几大协议
  • .htaccess配置重写url引擎
  • .NET Core/Framework 创建委托以大幅度提高反射调用的性能
  • .net 获取url的方法
  • /etc/sudoer文件配置简析
  • [100天算法】-x 的平方根(day 61)
  • [ACTF2020 新生赛]Upload 1
  • [AIGC] Kong:一个强大的 API 网关和服务平台
  • [C++] new和delete