进程与线程

进程:操作系统会以进程为单位,分配系统资源(CPU时间片、内存等资源)
线程:是CPU调度执行的最小单位,是指令序列

上下文切换

发生时机:进程自愿放弃它们在CPU中的时间,或者是调 度器在进程耗尽其CPU时间片时进行切换的结果
在内核态下完成,cpu密集型任务尽可能 地避免不必要的上下文切换
image.png
1. 暂停一个进程的处理,并将该进程的CPU状态(即上下文)存储在内存中的某个地方
2. 从内存中获取下一个进程的上下文,并在CPU的寄存器中恢复它
3. 返回到程序计数器指示的位置(即返回到进程被中断的代码行)以恢复进程。
cas不会涉及到用户态和内核态的切换

java线程

java线程属于内核级线程,线程的创建、撤销、切换都由内核执行。
java线程和虚拟机栈的关系:
每个方法被执行的时候,Java虚拟机都会同步创建一个栈帧,栈帧包括局部变量表、操作数栈、动态链接、方法返回地址和一些附加信息。这个栈帧可以理解为一个任务的载体,由cpu调度线程去执行任务

线程在操作系统层面是5种状态:初始 状态、可运行状态、运行状态、休眠状态和终止状态
java线程6种状态:
NEW (新建状态)、 RUNNABLE (就绪状态、运行状态)
BLOCKED (阻塞状态,和Synchronized相关)、
WAITING、TIMED_WAITING (等待)、TERMINATED(终止)

本质上Java中实现线程只有一种方式,都是通过new Thread()创建线程对象,调用Thread#start启动线程最终都会调用Thread#run方法�。编码方式可以是多种,直接new Thread(); 实现Runnable接口;Callable接口;线程池…

Java线程执行为什么不能直接调用run()方法,而要调用start()方法?

直接调用run()方法就不是真正地去创建线程。
在start方法中会调用本地方法,jvm会调用操作系统创建线程的方法,并完成os thread和java thread对象的绑定,将线程置为runnable状态,等os thread获取到cpu的使用权的时候,会回调执行java层面的run()方法的代码
start()源码分析:https://www.processon.com/view/link/5f02ed9e6376891e81fec8d5
image.png

java线程和go语言的协程有什么区别

协程,是一种比线程更加轻量级的存在,协程不是被操作系统内核所管理,而完全是由程序所控制(也就是在用户态执行),具有对内核来说不可见的特性

�协程的特点在于是一个线程执行,那和多线程比,协程有何优势?

  • 线程的切换由操作系统调度,协程由用户自己进行调度,因此减少了上下文切换,提 高了效率。
  • 线程的默认stack大小是1M,而协程更轻量,接近1k。因此可以在相同的内存中开启 更多的协程。

    注意: 协程适用于被阻塞的,且需要大量并发的场景(网络io)。不适合大量计算的场景。

  • 不需要多线程的锁机制:因为只有一个线程,也不存在同时写变量冲突,在协程中控 制共享资源不加锁,只需要判断状态就好了,所以执行效率比多线程高很多。

如何优雅地终止线程

java提供了中断机制,并不是直接终止另一个线程,而需要被中断的线程自己处理
api:

  • interrupt(): 将线程的中断标志位设置为true,不会停止线程
  • isInterrupted(): 判断当前线程的中断标志位是否为true,不会清除中断标志位
  • Thread.interrupted():判断当前线程的中断标志位是否为true,并清除中断标志 位,重置为fasle
  • Thread.sleep可以被中断 抛出中断异常:sleep interrupted, 清除中断标志位
  • wait可以被中断 抛出中断异常:InterruptedException, 清除中断标志位 ```java public class StopThread implements Runnable { @Override public void run() { int count = 0; while (!Thread.currentThread().isInterrupted() && count < 1000) { System.out.println(“count = “ + count++);
    1. }
    System.out.println(“线程停止: stop thread”); }

public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(new StopThread()); thread.start(); Thread.sleep(5); thread.interrupt(); } ```

java线程如何通信

1: volatile
利用 volatile的可见性去传递共享变量的变化
2:等待通知机制

  • 可以基于wait和notify方法来实现 ,但是需要在synchronized修饰的代码块中
  • LockSupport是JDK中用来实现线程阻塞和唤醒的工具,线程调用park则等待“许可”,调用 unpark则为指定线程提供“许可,相比于wait和notify方法功能更强大,所以java并发工具类中常用LockSupport这种方法