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

我们给出结果:
19:22:27 [t3] c.ThreadStarter - hello19:22:27 [main] c.ThreadStarter - 结果是:100我们给出简单解释:

  • FutureTask内置了一个Callable对象,初始化方法将指定的Callable赋给这个对象 。
  • FutureTask实现了Runnable接口 , 并重写了Run方法,在Run方法中调用了Callable中的call方法,并将返回值赋值给outcome变量
  • get方法就是取出outcome的值 。
多线程运行状况我们给出单核CPU运行多线程时不断切换进程的状况展示:
// 下述的操作不受我们控制,谁先调用,调用多久都不是我们管控的@Slf4j(topic = "c.TestMultiThread")public class TestMultiThread {public static void main(String[] args) {new Thread(() -> {while(true) {log.debug("running");}},"t1").start();new Thread(() -> {while(true) {log.debug("running");}},"t2").start();}}我们直接给出结果展示:
23:45:26.254 c.TestMultiThread [t2] - running23:45:26.254 c.TestMultiThread [t2] - running23:45:26.254 c.TestMultiThread [t2] - running23:45:26.254 c.TestMultiThread [t2] - running23:45:26.254 c.TestMultiThread [t1] - running23:45:26.254 c.TestMultiThread [t1] - running23:45:26.254 c.TestMultiThread [t1] - running23:45:26.254 c.TestMultiThread [t1] - running23:45:26.254 c.TestMultiThread [t1] - running23:45:26.254 c.TestMultiThread [t1] - running查看进程线程方法由于不同系统的查看方法不同,我们主要介绍三种类型查看方法
Window
  • 任务管理器可以查看进程和线程数 , 也可以用来杀死进程
  • tasklist 查看进程 :tasklist| findstr (查找关键字)
  • 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 进程中线程的运行情况(图形界面)
线程运行底层解释我们将会介绍两个与线程底层运行相关的原理
栈与栈帧下面我们来介绍一下与进程息息相关的底层原理:
  • 栈:存放栈帧的个体 , 每个线程具有一个单独的栈来存放多个栈帧
  • 栈?。悍椒ǖ娜磕诖嬲加? ,每个方法使用时的全部内存都用一个栈帧来表示
同时栈和栈帧也有一定限制:
  • 每个栈由多个栈?。‵rame)组成,对应着每次方法调用时所占用的内存
  • 每个线程只能有一个活动栈?。杂ψ诺鼻罢谥葱械哪歉龇椒?/li>
我们给出一个简单的代码展示:
// 这里展现的是单线程,目前只有一个栈!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 指令的执行地址,是线程私有的
  • 状态包括程序计数器、虚拟机栈中每个栈帧的信息,如局部变量、操作数栈、返回地址等
上下文切换时机: