学习笔记系列开头惯例发布一些寻亲消息
链接:https://baobeihuijia.com/bbhj/contents/3/199561.html
-
进程和线程:进程是资源分配的最小单位,线程是CPU调度的最小单位
- 进程和线程的主要区别(总结)_进程和线程的区别-CSDN博客
- 进程和线程的区别(超详细)-CSDN博客
- 在操作系统中能同时运行多个进程(程序);而在同一个进程(程序)中有多个线程同时执行
- 一个进程中可以有多个线程,多个线程共享进程的堆和**方法区 (JDK1.8 之后的元空间)*资源,但是每个线程有自己的*程序计数器、虚拟机栈 和 本地方法栈
-
并行和并发(从cpu的角度划分)
- 并发:任务调度器使得CPU在同一段时间执行不同的任务,微观串行,宏观并行
- 并行:在同一时刻cpu做多件事情的能力
-
异步同步(从方法的角度划分)
- 方法的执行需要等待别的结果返回,就是同步
- 不需要等待别的方法结果返回,就是异步
-
三种方法创建线程
# 方法一 Thread t = new Thread(){ public void run(){ xxxxx; } }; t.setName("t1") t.start(); # 方法二 Runnable r = new Runnable(){ public void run(){ xxxxxx; } } Thread t = new Thread(r,"t2") t.start(); # 方法三:简化lambda Runnable t = ()->{xxxxx;}; Thread t = new Thread(r,"t2") t.start(); # FutureTask是带有返回值的Runnable
# windows tasklist 查看所有进程 jps 显示所有的java进程 taskkill 杀死某个进程 # linux ps -fe 查看所有的命令进程 ps -fe | grep java 筛选带有Java的 jps 列出java进程 kill 4202 杀死进程 top 查看进程信息 top -H -p 4262 查看该进程的线程信息 jstack 4262 查看某个时刻的线程信息
-
字节码放到方法区(二进制格式)
-
jvm启动main线程,并分配main栈帧
- 线程上下文切换:cpu不再执行当前线程,转而执行另一个线程代码
- 线程的cpu时间片用完
- 垃圾回收
- 有更高优先级的线程
- 线程自己调用sleep,yield,wait,join,park,synchronized,lock方法
- context switch的时候,需要操作系统保存当前线程的状态,包括:
- 程序计数器、虚拟机栈中每个栈帧的信息(局部变量、操作数栈、返回地址)
-
知识点
-
start 和 run 的区别(start是由别的线程调用从而启动A线程的,调用后不会影响该线程的本身进度,run是由线程A分配到cpu后才执行的)
-
sleep和yield
- sleep就是放弃了cpu的使用,进入TIMED_WAITING阻塞状态
- yield:让线程从RUNNABLE变为RUNNABLE 就绪状态
- 在哪个线程下写 thread.sleep就是休眠哪个线程
- 状态: NEW — RUNNABLE(可以被cpu调用的) — TIMED_WAITING (休眠)
- 区别:cpu仍然会考虑yield,但是不会考虑sleep
-
线程优先级setPriority:只是一个提示,调度器可以忽略这个信号
-
join:等待线程运行结束,哪个线程调用就等待哪个线程
-
join(时间):等待 min(时间,线程执行时间)
-
interrupt
-
打断阻塞状态:sleep wait join 这些打断后isInterrupted重新置为false(打断后不能立即查看,需要等打断进入到异常块才能看到重置为false)
public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(() -> { log.debug("sleep..."); try { Thread.sleep(5000); // wait, join } catch (InterruptedException e) { e.printStackTrace(); } },"t1"); t1.start(); Thread.sleep(1000); log.debug("interrupt"); t1.interrupt(); // 这里如果没有等,可能还没有等t1重置为false就打印出true Thread.sleep(1000); log.debug("打断标记:{}", t1.isInterrupted()); }
-
打断正常状态:isInterrupted置为true,但是线程不会结束,需要自己再去判断是否真的要停止,获得currentThread(). isInterrupted 判断是否为true
@Slf4j(topic = "c.Test12") public class Test12 { public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(() -> { while(true) { boolean interrupted = Thread.currentThread().isInterrupted(); // 没有判断的话就一直不会停止 if(interrupted) { log.debug("被打断了, 退出循环"); break; } } }, "t1"); t1.start(); Thread.sleep(1000); log.debug("interrupt"); t1.interrupt(); } }
-
-
两阶段终止模式(A线程如何优雅的停止B线程)
``` @Slf4j(topic = "c.TwoPhaseTermination") class TwoPhaseTermination { // 监控线程 private Thread monitorThread; // 停止标记 private volatile boolean stop = false; // 判断是否执行过 start 方法 private boolean starting = false; // 启动监控线程 public void start() { synchronized (this) { if (starting) { // false return; } starting = true; } monitorThread = new Thread(() -> { while (true) { Thread current = Thread.currentThread(); // 是否被打断 if (stop) { log.debug("料理后事"); break; } try { Thread.sleep(1000); log.debug("执行监控记录"); } catch (InterruptedException e) { } } }, "monitor"); monitorThread.start(); } // 停止监控线程 public void stop() { stop = true; monitorThread.interrupt(); } } ```
-
park:代码会停止在执行park()的这一行,遇到interrupt后才会继续(标记为true),且以后再遇到park也不会停止,除非再次重置为false
-
不推荐用的:
- stop:强制让线程停止,即线程的资源可能还未被释放
- suspend:挂起线程
- resume 恢复线程运行
-
主线程和守护线程:只要其他非守护线程结束,那么即使守护线程没有运行结束,也会停止运行(垃圾回收线程)
t1.setDaemon(true); //设置守护线程
-
线程的状态(操作系统层面)
- 初始状态:仅语言层面创建线程对象,与操作系统未关联
- 可运行状态:cpu可以调度
- 运行状态:获取了cpu时间片
- 阻塞:
- 终止状态
-
线程六种状态(java层面)
- 初始状态:new但是尚未start
- RUNNABLE:start之后线程的运行状态,可运行状态,阻塞状态
- BLOCKED:拿不到锁
- WAITING:join
- TIMED_WAITING:sleep
- TERMINATED:终止
package cn.itcast.n3; import lombok.extern.slf4j.Slf4j; import java.io.IOException; @Slf4j(topic = "c.TestState") public class TestState { public static void main(String[] args) throws IOException { Thread t1 = new Thread("t1") { @Override public void run() { log.debug("running..."); } }; Thread t2 = new Thread("t2") { @Override public void run() { while(true) { // runnable } } }; t2.start(); Thread t3 = new Thread("t3") { @Override public void run() { log.debug("running..."); } }; t3.start(); Thread t4 = new Thread("t4") { @Override public void run() { synchronized (TestState.class) { try { Thread.sleep(1000000); // timed_waiting } catch (InterruptedException e) { e.printStackTrace(); } } } }; t4.start(); Thread t5 = new Thread("t5") { @Override public void run() { try { t2.join(); // waiting } catch (InterruptedException e) { e.printStackTrace(); } } }; t5.start(); Thread t6 = new Thread("t6") { @Override public void run() { synchronized (TestState.class) { // blocked try { Thread.sleep(1000000); } catch (InterruptedException e) { e.printStackTrace(); } } } }; t6.start(); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } log.debug("t1 state {}", t1.getState()); log.debug("t2 state {}", t2.getState()); log.debug("t3 state {}", t3.getState()); log.debug("t4 state {}", t4.getState()); log.debug("t5 state {}", t5.getState()); log.debug("t6 state {}", t6.getState()); System.in.read(); } }
-