JUC学习笔记——进程与线程( 四 )

  • taskkill 杀死进程:taskkill /F(彻底杀死)/PID(进程PID)
  • Linux
    • ps -fe 查看所有进程
    • ps -fT -p查看某个进程(PID)的所有线程
    • kill 杀死进程 top 按大写 H 切换是否显示线程
    • top -H -p查看某个进程(PID)的所有线程
    Java
    • jps 命令查看所有 Java 进程
    • jstack查看某个 Java 进程(PID)的所有线程状态
    • jconsole 来查看某个 Java 进程中线程的运行情况(图形界面)
    线程运行底层解释我们将会介绍两个与线程底层运行相关的原理
    栈与栈帧下面我们来介绍一下与进程息息相关的底层原理:
    • 栈:存放栈帧的个体,每个线程具有一个单独的栈来存放多个栈帧
    • 栈帧:方法的全部内存占用,每个方法使用时的全部内存都用一个栈帧来表示
    同时栈和栈帧也有一定限制:
    • 每个栈由多个栈帧(Frame)组成,对应着每次方法调用时所占用的内存
    • 每个线程只能有一个活动栈帧,对应着当前正在执行的那个方法
    我们给出一个简单的代码展示:
    // 这里展现的是单线程,目前只有一个栈!package cn.itcast.n3;public class TestFrames {// 首先main方法被调用,所以main方法先进入栈中,在main方法执行结束后被抛出栈public static void main(String[] args) {method1(10);}// 由于main方法调用了method1,所以栈中在存有main栈帧的同时也将method1栈帧调入,在method1方法执行完毕后抛出private static void method1(int x) {int y = x + 1;Object m = method2();System.out.println(m);}// 由于method1方法调用了method2,所以栈中在存有main,method1栈帧的同时也将method2栈帧调入,method2方法执行完毕后抛出private static Object method2() {Object n = new Object();return n;}}// 这里展现的是多线程,主线程和线程t1独自各占有一个栈,互不影响!package cn.itcast.n3;public class TestFrames {// 这里会产生两个栈,两个栈互不影响,两个栈都会顺序调用main,method1,method2栈帧,顺序不定public static void main(String[] args) {Thread t1 = new Thread(){@Overridepublic void run() {method1(20);}};t1.setName("t1");t1.start();method1(10);}private static void method1(int x) {int y = x + 1;Object m = method2();System.out.println(m);}private static Object method2() {Object n = new Object();return n;}}线程上下文切换我们再来介绍一下上下文切换:
    • 当出现一些状况时,系统会自动将CPU的使用权进行切换,交付给不同的线程进行使用
    上下文切换措施:
    • 要由操作系统保存当前线程的状态,并恢复另一个线程的状态,
    • Java 中对应的就是程序计数器,它的作用是记住下一条 jvm 指令的执行地址,是线程私有的
    • 状态包括程序计数器、虚拟机栈中每个栈帧的信息,如局部变量、操作数栈、返回地址等
    上下文切换时机:
    • 线程的 cpu 时间片用完
    • 垃圾回收
    • 有更高优先级的线程需要运行
    • 线程自己调用了 sleep、yield、wait、join、park、synchronized、lock 等方法
    但是我们需要注意:
    • Context Switch 频繁发生会影响性能
    线程方法详解这一小节我们将介绍线程的各种方法
    线程方法总述我们首先给出线程的全部方法一览:
    方法功能说明public void start()启动一个新线程;Java虚拟机调用此线程的run方法start 方法只是让线程进入就绪,里面代码不一定立刻 运行(CPU 的时间片还没分给它) 。每个线程对象的 start方法只能调用一次,如果调用了多次会出现 IllegalThreadStateExceptionpublic void run()线程启动后调用该方法如果在构造 Thread 对象时传递了 Runnable 参数,则 线程启动后会调用 Runnable 中的 run 方法,否则默 认不执行任何操作 。但可以创建 Thread 的子类对象,来覆盖默认行为public void setName(String name)给当前线程取名字public void getName()获取当前线程的名字 。线程存在默认名称:子线程是Thread-索引,主线程是mainpublic static Thread currentThread()获取当前线程对象,代码在哪个线程中执行public static void sleep(long time)让当前线程休眠多少毫秒再继续执行 。Thread.sleep(0) : 让操作系统立刻重新进行一次cpu竞争public static native void yield()提示线程调度器让出当前线程对CPU的使用主要是为了测试和调试public final int getPriority()返回此线程的优先级public final void setPriority(int priority)更改此线程的优先级,常用1 5 10java中规定线程优先级是1~10 的整数,较大的优先级 能提高该线程被 CPU 调度的机率public void interrupt()中断这个线程,异常处理机制public static boolean interrupted()判断当前线程是否被打断,清除打断标记public boolean isInterrupted()判断当前线程是否被打断,不清除打断标记public final void join()等待这个线程结束public final void join(long millis)等待这个线程死亡millis毫秒,0意味着永远等待public final native boolean isAlive()线程是否存活(还没有运行完毕)public final void setDaemon(boolean on)将此线程标记为守护线程或用户线程public long getId()获取线程长整型 的 idid 唯一public state getState()获取线程状态Java 中线程状态是用 6 个 enum 表示,分别为: NEW, RUNNABLE, BLOCKED, WAITING,TIMED_WAITING, TERMINATEDpublic boolean isInterrupted()判断是否被打 断不会清除 打断标记start与run我们首先来介绍线程的两个相似的启动方法:

    经验总结扩展阅读