剑指JUC原理-2.线程

news2024/12/23 12:39:50

创建和运行线程

直接使用Thread

// 创建线程对象
Thread t = new Thread() {
 public void run() {
 // 要执行的任务
 }
};
// 启动线程
t.start();

--------------------------------------------------
    
// 构造方法的参数是给线程指定名字,推荐
Thread t1 = new Thread("t1") {
 @Override
 // run 方法内实现了要执行的任务
 public void run() {
 log.debug("hello");
 }
};
t1.start();

输出:
19:19:00 [t1] c.ThreadStarter - hello

使用Runnable配合Thread

其特点是:把“线程”和“任务”(要执行的代码)分开

Thread代表线程

Runnable代表可运行的任务(线程要执行的代码)

Runnable runnable = new Runnable() {
 public void run(){
 // 要执行的任务
 }
};
// 创建线程对象
Thread t = new Thread( runnable );
// 启动线程
t.start(); 

--------------------------------------------------
    
// 创建任务对象
Runnable task2 = new Runnable() {
 @Override
 public void run() {
 log.debug("hello");
 }
};
// 参数1 是任务对象; 参数2 是线程名字,推荐
Thread t2 = new Thread(task2, "t2");
t2.start();

输出:
19:19:00 [t2] c.ThreadStarter - hello

在java8以后,可以使用lambda来精简代码,快捷键是选中Runnable alt + enter

Runnable task2 = () -> log.debug("hello");
// 参数1 是任务对象; 参数2 是线程名字,推荐
Thread t2 = new Thread(task2, "t2");
t2.start();

之所以Runnable能使用lambda,主要是Runnable接口有@FunctionalInterface,该注解只允许存在一个接口方法。

Thread和Runnable的关系(源码)

在这里插入图片描述

通过定位源码发现 Runnable的实现方式,其实走的还是run方法,有Runnable的还是优先执行Runnable的run方法,而Thread本身的实现其实就是重写了run方法。

总结:
  • Thread是把线程和任务合并在了一起,Runnable是把线程和任务分开了
  • 用 Runnable 更容易与线程池等高级 API 配合
  • 用 Runnable 让任务类脱离了 Thread 继承体系,更灵活

FutureTask配置Thread

FutureTask 能够接收 Callable 类型的参数,用来处理有返回结果的情况

// 创建任务对象
FutureTask<Integer> task3 = new FutureTask<>(() -> {
 log.debug("hello");
 return 100;
});
// 参数1 是任务对象; 参数2 是线程名字,推荐
new Thread(task3, "t3").start();
// 主线程阻塞,同步等待 task 执行完毕的结果
Integer result = task3.get();
log.debug("结果是:{}", result);

输出:
19:22:27 [t3] c.ThreadStarter - hello
19:22:27 [main] c.ThreadStarter - 结果是:100

FutureTask代码分析

在这里插入图片描述

其中get方法是一个主线程阻塞同步等待task执行完毕的结果

多线程同时执行

public static void main(String[] args) {
        new Thread(() -> {
            while(true) {
                log.debug("running");
            }
        },"t1").start();
        new Thread(() -> {
            while(true) {
                log.debug("running");
            }
        },"t2").start();
    }

实际的输出结果是交替执行,谁先谁后并不由我们来控制,是由底层的任务调度器来决定的。

查看进行线程的方法

windows

任务管理器可以查看进程和线程数,也可以用来杀死进程

在这里插入图片描述

tasklist 查看所有进程

taskkill 进程号 杀死某个进程

java

jps 命令查看所有 Java 进程

jstack 查看某个 Java 进程(PID)的所有线程状态

linux

ps -fe 查看所有进程
ps -fT -p 查看某个进程(PID)的所有线程
kill 杀死进程
top 按大写 H 切换是否显示线程
top -H -p 查看某个进程(PID)的所有线程

线程运行之原理

栈与栈帧

Java Virtual Machine Stacks (Java 虚拟机栈)
我们都知道 JVM 中由堆、栈、方法区所组成,其中栈内存是给谁用的呢?其实就是线程,每个线程启动后,虚拟
机就会为其分配一块栈内存。

  • 每个栈由多个栈帧(Frame)组成,对应着每次方法调用时所占用的内存
  • 每个线程只能有一个活动栈帧,对应着当前正在执行的那个方法

以debug的方式来介绍栈帧

	public static void main(String[] args) {
        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;
    }

我们对method1 打上断点进行debug

在这里插入图片描述

首先可以看到main先进入了栈帧中,其Variables中 有其参数

当继续进行的时候,此时method1进入栈帧,同时其Variables 包含其入参

在这里插入图片描述

继续执行,其Variables 包含其局部变量

在这里插入图片描述

继续执行,此时method2进入栈帧

在这里插入图片描述

然后是返回n

在这里插入图片描述

由于栈的数据结构是先进先出的,当执行完毕后,会对method2进行释放

在这里插入图片描述

以上就是栈帧的整个执行流程了。

图解线程流程

在这里插入图片描述

最开始是执行一个类加载,将类加载到java虚拟机中,加载的位置是将字节码放置在方法区

类加载完成后,java虚拟机就会启动一个main的主线程,给主线程分配一块栈内存,此时线程就交给任务调度器调度执行

如果cpu分配给我们的主线程了

在这里插入图片描述

虚拟机会给main方法分配一块栈帧内存

在这里插入图片描述

当然每个栈内存中还存在一个程序计数器的组件,它是每个线程私有的,记录了我当前该执行哪行代码,cpu就向程序计数器要 是什么

在这里插入图片描述

在这里插入图片描述

局部变量表其实是创建时其实就已经分配好了,不是运行到某行代码时才分配内存

其中method1栈帧中 x = 10,并且相应的语句也会逐渐的到程序计数器中

在这里插入图片描述

在这里插入图片描述

然后的流程其实就是和debug一样,逐层的释放掉了

多线程运行原理

public static void main(String[] args) {
        Thread t1 = new Thread(){
            @Override
            public void run() {
                method1(20);
                // 断点模式 要选择 thread 不要选择 all
            }
        };
        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;
    }

此时的断点模式要选择 Thread

在这里插入图片描述

其实本质上和单线程是一样的,不同点在于,每个线程都有一个自己私有的栈,每个栈里面还是个单线程一样,但是线程切换的话,会保存当前的操作。其实最本质的就是要理解,每个栈内存是相互独立的。

线程上下文切换

因为以下一些原因导致 cpu 不再执行当前的线程,转而执行另一个线程的代码

  • 线程的 cpu 时间片用完
  • 垃圾回收
  • 有更高优先级的线程需要运行
  • 线程自己调用了 sleep、yield、wait、join、park、synchronized、lock 等方法

当 Context Switch 发生时,需要由操作系统保存当前线程的状态,并恢复另一个线程的状态,Java 中对应的概念
就是程序计数器(Program Counter Register),它的作用是记住下一条 jvm 指令的执行地址,是线程私有的

  • 状态包括程序计数器、虚拟机栈中每个栈帧的信息,如局部变量、操作数栈、返回地址等
  • Context Switch 频繁发生会影响性能

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1147933.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

力扣 三数之和 双指针 java

Problem: 15. 三数之和 时间复杂度: O ( n 2 ) O(n^2) O(n2) &#x1f351; AC code class Solution {public List<List<Integer>> threeSum(int[] nums) {List<List<Integer>> res new ArrayList<>();int len nums.length; if(len < 3…

【卷积神经网络】YOLO 算法原理

在计算机视觉领域中&#xff0c;目标检测&#xff08;Object Detection&#xff09;是一个具有挑战性且重要的新兴研究方向。目标检测不仅要预测图片中是否包含待检测的目标&#xff0c;还需要在图片中指出它们的位置。2015 年&#xff0c;Joseph Redmon, Santosh Divvala 等人…

No173.精选前端面试题,享受每天的挑战和学习

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云课上架的前后端实战课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你从入…

队列概念|循环队列的实现

前言 今天我们将学习循环队列实现&#xff0c;我们首先介绍队列的概念和结构&#xff0c;之后一步步讲解循环队列由来与实现。 一、队列的概念与结构 1、队列的概念 队列&#xff1a; 只允许在一端进行插入数据操作&#xff0c;在另一端进行删除数据操作的特殊线性表。队列是…

3.72 Command Buffer及URP概述

一、Command Buffer 1.概念 CommandBuffer携带一系列的渲染命令&#xff0c;依赖相机&#xff0c;用来拓展渲染管线的渲染效果。而且可以指定在相机渲染的某个点执行本身的拓展渲染。Command buffers也可以结合屏幕后期效果使用。 简单来说就是可以在渲染流程中插入一些自定…

群智能算法之模拟退火算法

1.模拟退火算法简介&#xff1a; 2.模拟退火算法的关键点&#xff1a; &#xff08;1&#xff09;随机的更新可行解x,判断可行解x对应的函数值和原来函数值之间的大小&#xff1a;如果优于原来的函数值&#xff0c;则让新的可行解x为问题的解&#xff1b;否则以一定的概率(大于…

centos7 部署 Flink

1. 准备 安装的前提是虚拟机里已安装了jdk 去官网下载 Flink 所有版本下载地址&#xff1a;https://archive.apache.org/dist/flink/ 找到下图的安装包&#xff0c;下载即可 下载完后&#xff0c;将其上传至虚拟机的某个地方&#xff0c;本人将其放在 /home/flink/ 下 解压…

nacos面试题

Nacos中保证的是CP还是AP&#xff1f; 通常我们说&#xff0c;Nacos技能保证CP&#xff0c;也能保证AP&#xff0c;具体看如何配置&#xff0c;但其实只不过是Nacos中的注册中心能保证CP或AP&#xff0c;Nacos中的配置中心其实没什么CP或AP&#xff0c;因为配置中心的数据是存在…

2023.10.28 关于 synchronized 原理

目录 synchronized 特性 synchronized 优化机制 锁升级&#xff08;锁膨胀&#xff09; 其他优化机制 锁消除 锁粗化 synchronized 特性 开始时是乐观锁&#xff0c;如果锁冲突频繁&#xff0c;就转为悲观锁开始是轻量级锁&#xff0c;如果锁被持有的时间较长&#xff0c…

水果百科网站 vue+uniapp微信小程序设计与实现

设计并实现了鲜而廉水果微信小程序。系统选用java语言&#xff0c;应用Springboot框架&#xff0c; MySQL为后台数据库。系统主要包括用户、水果百科、水果视频、交流论坛等功能模块。 经过认真细致的研究&#xff0c;精心准备和规划&#xff0c;最后测试成功&#xff0c;系统可…

[导弹打飞机H5动画制作]飞机与导弹的碰撞检测

界面参考: 代码参考: this.btnShootTruck.addEventListener("click", startShoot); var _this = this; _this.ShootFire.stop(); _this.ShootFire.alpha = 0; //_this.AsyPlaneObj.gotoAndStop(0); _this.AsyPlaneObj.alpha = 1; _this.AsyPlaneObj.BombPlaneObj.al…

【vtk学习笔记2】vtk编程中的基本对象

一、VTK编程中的基本对象 数据可视化一般需要一个数据源&#xff0c;可以来说具体的算法&#xff0c;如有限元、边界元等&#xff0c;也可以是测量数据&#xff0c;如医学检测数据等。这些基础数据经过变换处理&#xff0c;变成计算机图形流水线支持的数据&#xff0c;最后显示…

redis实现分布式延时队列

文章目录 延时队列简介应用场景案例&#xff1a;考虑&#xff1a;实现&#xff1a;整体思路&#xff1a;具体实现生产者消费者 运行结果 redis分布式延时队列优势redis分布式延时队列劣势 延时队列简介 延时队列是一种特殊的消息队列&#xff0c;它允许将消息在一定的延迟时间…

【系统安全】等保二级、三级自查对比

目录 1、定义&#xff1a;二级 VS 三级 2、要求&#xff1a;二级 VS 三级 3、适用企业、单位 1、定义&#xff1a;二级 VS 三级 等保&#xff1a;全称网络安全等级保护&#xff0c;是指对信息系统进行分级&#xff0c;对不同等级的信息系统进行不同的安全保护和监管的工作。…

仿写知乎日报第二周

新学到的 新学到了WKWebView&#xff1a; WKWebView是是苹果推崇的一个新的类&#xff0c;它用于将一个网页嵌套在软件里。这里我是将点击cell后的内容中放入WKWebView对象。WKWebView的使用&#xff1a; 首先&#xff0c;要导入这个类&#xff1a; #import <WebKit/WebK…

3.7 移动端TB(D)R架构基础

一、各类电子设备功耗对比 桌面级主流性能平台&#xff0c;功耗一般为300W&#xff08;R7/I7X60级别显卡&#xff09;&#xff0c;游戏主机150-200W入门和旗舰游戏本平台功耗为100W主流笔记本为50-60W&#xff0c;超极本为15-25W&#xff0c;旗舰平板为8-15W旗舰手机为5-8W&am…

《python语言程序设计》(2018版)第5章编程题 第41题第3次路过。总结一下。没有走完的路

这道题最大的需要就是能够进行两个数值的对比&#xff0c;同时还能让更多的数值依次进入到对比中。 这道题的解题版本 这个版本只是能统计出谁是最大数。但是无法统计最大数出现了多少次。 number "" count 0 data_number 0 while number ! 0:number eval(inpu…

No172.精选前端面试题,享受每天的挑战和学习

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云课上架的前后端实战课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你从入…

MinIO安装

Minio是一个开源的分布式对象存储服务器&#xff0c;它兼容Amazon S3服务接口。它可以用于构建私有云存储&#xff0c;为应用程序提供可扩展的对象存储功能。 安装 docker安装 docker run -d -p 9000:9000 -p 50000:50000 --name minio \ -e "MINIO_ROOT_USERadminpili…

泰州市旅游景点门票预订管理系统 vue+uniapp微信小程序

本文从管理员、用户的功能要求出发&#xff0c;泰州市旅游景点管理小程序中的功能模块主要是实现用户、景点类型、景区信息、门票预定。经过认真细致的研究&#xff0c;精心准备和规划&#xff0c;最后测试成功&#xff0c;系统可以正常使用。分析功能调整与泰州市旅游景点管理…