创建和运行线程方式
方法一:继承Thread类,重写run方法
方法二:实现Runnable接口,把对象传入Thread。把【线程】和【任务】分开
原理区别:方法一是子类重写了Thread类的run方法,然后执行。
方法二把runnable类的target实例传给Thread类,执行了自己的任务。
总结:
推荐用runnable接口。
- 方法1 是把线程和任务合并在了一起,方法2 是把线程和任务分开了 用
- Runnable 更容易与线程池等高级 API 配合用
- Runnable 让任务类脱离了 Thread 继承体系,更灵活
查看进程线程的方法
Windows
- 任务管理器可以查看进程和线程数,也可以用来杀死进程
- tasklist 查看进程
- taskkill 杀死进程
Linux
- ps -fe 查看所有进程
- ps -fT -p 查看某个进程(PID)的所有线程
- kill 杀死进程
- top 按大写 H 切换是否显示线程
- top -H -p 查看某个进程(PID)的所有线程
JDK自带
- jps 命令查看所有 Java 进程
- jstack 查看某个 Java 进程(PID)的所有线程状态
- jconsole 来查看某个 Java 进程中线程的运行情况(图形界面)
线程运行原理
栈与栈帧
Java Virtual Machine Stacks (Java 虚拟机栈)
我们都知道 JVM 中由堆、栈、方法区所组成,其中栈内存是给谁用的呢?其实就是线程,每个线程启动后,虚拟机就会为其分配一块栈内存。
- 每个栈由多个栈帧(Frame)组成,对应着每次方法调用时所占用的内存
- 每个线程只能有一个活动栈帧,对应着当前正在执行的那个方法
代码与图示
当运行到method1里sout(m)前的栈帧图示,程序计数器用来记录代码执行到哪行
当多个线程同时运行时,每个线程有自己独立的栈内存,里面有自己的栈帧,相互之间互不干扰