线程和进程(juc)

线程

一:概念辨析

1:线程与进程

进程:

1:程序由指令和数据组成,指令要执行,数据要读写,就需要将指令加载给cpu,把数据加载到内存,同时程序运行时还会使用磁盘,网络等资源。进程就是负责管理内存,加载指令,管理io的;

2:当一个程序运行时就会将程序的相关代码加载到内存中,这就开启了一个进程;

3:一个程序的实例就是进程,有的程序可以有多个实例进程,有的程序只能有一个实例进程;


线程:

1:一个进程内会有一个或多个线程

2:一个线程就是一个指令流,将指令一条条按照顺序加载给cpu执行;

3:在java中,线程是最小调度单位,进程是最小资源管理单位。在windows中进程是不活动的只是作为线程的容器;


线程和进程对比:

1:进程是相对独立的,线程存在于进程,是进程的一个子集;

2:进程有共享的资源,如共享的内存;

3:进程间的通信,分为同一个计算机和不同计算机:

同一个计算机进行通信较为简单,称为ipc;

不同计算机的进程进行通信需要借助于网络,并且遵守相同的协议如http;

4:线程间通信较为简单,因为他们共享进程的资源;

5:线程更轻量,线程切换上下文比进程切换上下文的成本更低;

2:并发和并行的概念:

并发:在单核cpu下线程实际上是串行执行的,操作系统中有个组件叫任务调度器,它会将cpu的时间片轮流交给不同的线程使用,由于时间片很短,cpu在不同的线程进行切换人类感知不到,所以就会感觉是同时运行的。总结一下就是:微观串行,宏观并行

像这种,线程轮流使用cpu的情况就叫做并发;

而在多核cpu下,每个核都可以调度线程,这个时候就是并行的;

使用golang的创作者的一句话就是:并发:是同时应对多件事的能力;(deal with)

并行:是同时做多件事的能力;(do)

二:应用

1:异步调用:

同步调用:需要等待结果返回才能执行下面的代码;

异步调用:无需等待结果的返回就能执行下面的代码;

2:提升效率:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

注意单核cpu使用多线程与单核cpu使用单线程的性能差距不是很大;

多核cpu和单核cpu执行的性能有很大差别;

三:创建

1:使用thread的内部类

public static void main(String[] args) {
    Thread t=new Thread(){
        @Override
        public void run() {
            log.debug("new thread");
        }
    };
    t.setName("t1");
    t.start();
    log.debug("main");
}

t.setName(“t1”);来给线程命名。run方法指定要执行的任务,start启动线程;

2:使用runnable配合thread

将线程和任务分开:runnable来定义任务,thread创建线程:

public static void main(String[] args) {
   Runnable runnable= new Runnable(){
        @Override
        public void run() {
            log.debug("running");
        }
    };
    Thread thread = new Thread(runnable);
    thread.setName("t1");
    thread.start();
    log.debug("running");
}

java8之后可以使用lamda表达式来简化语句:

public static void main(String[] args) {
  /* Runnable runnable= new Runnable(){
        @Override
        public void run() {
            log.debug("running");
        }
    };*/
    Runnable runnable =() ->log.debug("running");
    Thread thread = new Thread(runnable);
    thread.setName("t1");
    thread.start();
    log.debug("running");
}

或者:

public static void main(String[] args) {
  /* Runnable runnable= new Runnable(){
        @Override
        public void run() {
            log.debug("running");
        }
    };*/
 /*   Runnable runnable =() ->log.debug("running");*/
    Thread thread = new Thread(()->log.debug("running"),"t1");
    /*thread.setName("t1");*/
    thread.start();
    log.debug("running");
}

3:使用futureTask配合thread

public static void main(String[] args) throws ExecutionException, InterruptedException {
    FutureTask<Integer> integerFutureTask = new FutureTask<Integer>(new Callable<Integer>() {
        @Override
        public Integer call() throws Exception {
            log.debug("running");
            return 100;
        }
    });
    Thread thread=new Thread(integerFutureTask,"t1");
    thread.start();
    log.debug("{}",integerFutureTask.get());

}

futuretask继承了runnable接口,futuretask能够接收callable参数;

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

调用get方法时会阻塞等待,等待线程执行完毕然后返回结果;

四:查看

1:windows

window查看进程:

  • 使用任务管理器查看
  • 命令行:tasklist:查看所有进程
  • 杀死进程:taskkill

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2:linux

linux查看进程:

  • ps命令,结合管道运算符。
  • top命令动态的查看进程;

杀死进程:

  • kill 【进程id】

查看线程:

  • top -H -p 【进程id】

-H表示查看线程,-p指定进程id;

3:java

  • 查看进程:jps
  • 查看线程:jstack 【进程id】

五:原理

上下文切换

  • 什么是线程的上下文切换:

    当cpu暂停执行当前线程,开始执行下一个线程的时候会产生上下文切换;

  • 什么情况下会导致上下文切换

    1:cpu的时间片用完

    2:垃圾回收

    3:优先级更高的线程执行;

    4:主动调用一些方法如sleep,yield,join,wait,lock等

    当上下文切换时就需要保存当前线程的状态,并且恢复另一个线程的状态。jvm有一个组件叫程序计数器,它的作用是来记录下一条指令的执行地址,程序计数器是线程私有的;

    保存线程的状态不止程序计数器,还需要保存虚拟机栈中的栈帧信息;

    频繁的上下文切换会影响性能;

六:常见方法

1:start和run方法

start:

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

结果:

16:20:03.992 [t1] DEBUG org.example.Field.test1 - start

run:

public static void main(String[] args) {
    new Thread(()->log.debug("run"),"t1").run();
}

结果:

16:22:07.587 [main] DEBUG org.example.Field.test1 - run

可以看到run没有创建一个新的线程,没法达到异步调用的效果;start可以;

start不能调用多次,不然会报错。

2:sleep

1:状态:
public static void main(String[] args) {
    Thread t1 = new Thread(() -> {
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }, "t1");
    t1.start();
    log.debug("state:{}",t1.getState());
    try {
        Thread.sleep(500);
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }
    log.debug("state:{}",t1.getState());
}

输出:

16:32:08.998 [main] DEBUG org.example.Field.test2 - state:RUNNABLE
16:32:09.512 [main] DEBUG org.example.Field.test2 - state:TIMED_WAITING

可以看到,调用sleep方法之后线程会进入time-waiting状态;

那个线程里调用sleep,那个线程就休眠

2:打断

调用interrupt方法可以打断休眠的线程,但是会抛出异常:

public static void main(String[] args) {
    Thread t1 = new Thread(() -> {
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }, "t1");
    t1.start();
    log.debug("state:{}",t1.getState());
    try {
        Thread.sleep(500);
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }
    t1.interrupt();
    log.debug("state:{}",t1.getState());
}

结果:

16:36:26.912 [main] DEBUG org.example.Field.test2 - state:RUNNABLE
16:36:27.416 [main] DEBUG org.example.Field.test2 - state:TIMED_WAITING
Exception in thread "t1" java.lang.RuntimeException: java.lang.InterruptedException: sleep interrupted
	at org.example.Field.test2.lambda$main$0(test2.java:18)
	at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: java.lang.InterruptedException: sleep interrupted
	at java.base/java.lang.Thread.sleep(Native Method)
	at org.example.Field.test2.lambda$main$0(test2.java:16)
	... 1 more
3:yield和sleep的区别

调用yield后线程的状态会从running状态转变为runnable就绪状态状态,然后去调用其他线程;具体的实现依赖于操作系统的任务调度器

和sleep的区别是,调用sleep进入time-wait状态不会被cpu调用,而调用yield进入就绪状态还是有可能被cpu调用的;

3:线程优先级

  • 线程的优先级会提示调度器优先执行该线程,但是只是一个提示,调度器可以忽略;
  • 当cpu较忙时会给优先级高的线程分配较长的时间片,cpu较闲时,优先级几乎没有作用;

4:join

join:等待线程运行结束;

join(时间):设置最大等待时间,如果超过最大等待时间则不再等待,如果没超过就执行完毕直接返回;

5:interrupt

打断线程

1:打断阻塞:

打断sleep,wait,join的线程;

打断后会抛出异常;

然后打断标记会变成true;

2:打断正常:

打断正常的线程不会使线程停止运行,只会将打断标记变为true;

public static void main(String[] args) throws InterruptedException {
    Thread thread = new Thread(() -> {
        while (true) {

        }
    }, "t1");
    thread.start();
    Thread.sleep(1000);
    log.debug("interrupt");
    thread.interrupt();
    log.debug("is,{}",thread.isInterrupted());
}
18:43:44.479 [main] DEBUG org.example.Field.test3 - interrupt
18:43:44.481 [main] DEBUG org.example.Field.test3 - is,true

但是会一直执行;

可以进行判断然后打断线程:

public static void main(String[] args) throws InterruptedException {
    Thread thread = new Thread(() -> {
        while (true) {
            Thread thread1 = Thread.currentThread();
            if (thread1.isInterrupted()) {
                log.debug("被打断了");
                break;
            }
        }
    }, "t1");
    thread.start();
    Thread.sleep(1000);
    log.debug("interrupt");
    thread.interrupt();
    log.debug("is,{}",thread.isInterrupted());
18:48:49.671 [main] DEBUG org.example.Field.test3 - interrupt
18:48:49.672 [t1] DEBUG org.example.Field.test3 - 被打断了
18:48:49.672 [main] DEBUG org.example.Field.test3 - is,true
``

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

五、docker的网络模式

五、docker的网络模式 5.1 Docker的四种网络模式 当你安装docker时&#xff0c;它会自动创建三个网络&#xff0c;可使用如下命令查看&#xff1a; [rootlocalhost ~]# docker network ls NETWORK ID NAME DRIVER SCOPE 7390284b02d6 bridge bridge lo…

【AWS re:Invent 2024】一文了解EKS新功能:Amazon EKS Auto Mode

文章目录 一、为什么要使用 Amazon EKS Auto Mode&#xff1f;二、Amazon EKS自动模式特性2.1 持续优化计算成本2.2 迁移集群操作2.3 EKS 自动模式的高级功能 三、EKS Auto 集群快速创建集群配置四、查看来自 API 服务器的指标五、EKS 相关角色权限设置六、参考链接 一、为什么…

数据结构——有序二叉树的删除

在上一篇博客中&#xff0c;我们介绍了有序二叉树的构建、遍历、查找。 数据结构——有序二叉树的构建&遍历&查找-CSDN博客文章浏览阅读707次&#xff0c;点赞18次&#xff0c;收藏6次。因为数据的类型决定数据在内存中的存储形式。left right示意为左右节点其类型也为…

git pull error: cannot lock ref

Git: cannot lock ref ‘refs/remotes/origin/feature/xxx’: refs/remotes/origin/feature/xxx/car’ exists; cannot create refs/remotes/origin/feature/xxx git remote prune origin重新整理服务端和本地的关联关系即可

树与图深度优先遍历——acwing

题目一&#xff1a;树的重心 846. 树的重心 - AcWing题库 分析 采用暴力枚举&#xff0c;试探每个点&#xff0c;除去之后&#xff0c;连通分量最大值是多少&#xff0c; 各个点的最大值找最小的 因为可以通过 dfs 来得到 根u以下点数&#xff0c;以及可以求各分树的点数&am…

ultralytics-YOLOv11的目标检测解析

1. Python的调用 from ultralytics import YOLO import os def detect_predict():model YOLO(../weights/yolo11n.pt)print(model)results model(../ultralytics/assets/bus.jpg)if not os.path.exists(results[0].save_dir):os.makedirs(results[0].save_dir)for result in…

图形开发基础之在WinForms中使用OpenTK.GLControl进行图形绘制

前言 GLControl 是 OpenTK 库中一个重要的控件&#xff0c;专门用于在 Windows Forms 应用程序中集成 OpenGL 图形渲染。通过 GLControl&#xff0c;可以轻松地将 OpenGL 的高性能图形绘制功能嵌入到传统的桌面应用程序中。 1. GLControl 的核心功能 OpenGL 渲染上下文&…

Facebook广告文案流量秘诀

Facebook 广告文案是制作有效 Facebook 广告的关键方面。它侧重于伴随广告视觉元素的文本内容。今天我们的博客将深入探讨成功的 Facebook 广告文案的秘密&#xff01; 一、广告文案怎么写&#xff1f; 正文&#xff1a;这是帖子的正文&#xff0c;出现在您姓名的正下方。它可…

java面向对象实验——扫雷+24点

扫雷 窗口绘制&#xff1a; GameWin package com.sxt;import javax.swing.*;public class GameWin extends JFrame {void launch(){this.setVisible(true);this.setSize(500, 500);this.setLocationRelativeTo(null);this.setTitle("SWE23070扫雷游戏");this.setD…

Ubuntu24安装 python3-mysql.connector

正确命令 sudo apt install python3-mysql.connector说明 网络上已有的文章Python版本和Ubuntu版本旧&#xff0c;命令不生效。

【西门子PLC.博途】——在S71200里写时间设置和读取功能块

之前我们在这篇文章中介绍过如何读取PLC的系统时间。我们来看看在西门子1200里面有什么区别。同时也欢迎关注gzh。 我们在S71200的帮助文档中搜索时间后找到这个数据类型 在博途中他是一个结构体&#xff0c;具体为 然后我们再看看它带的读取和写入时间块 读取时间&#xff1…

如何搭建智慧工厂?IOT+AI:赋能未来制造业灯塔工厂建设

在当今数字化和智能化的浪潮中&#xff0c;传统制造业正经历着前所未有的变革。智慧工厂作为智能制造的核心内容&#xff0c;正逐步成为未来制造业的发展趋势。本文将深入探讨智慧工厂的搭建过程&#xff0c;以及IoT&#xff08;物联网&#xff09;和AI&#xff08;人工智能&am…

内存图及其画法

所有的文件都存在硬盘上&#xff0c;首次使用的时候才会进入内存 进程&#xff1a;有自己的Main方法&#xff0c;并且依赖自己Main运行起来的程序。独占一块内存区域&#xff0c;互不干扰。内存中有一个一个的进程。 操作系统只认识c语言。操作系统调度驱动管理硬件&#xff0…

Linux下,用ufw实现端口关闭、流量控制(二)

本文是 网安小白的端口关闭实践 的续篇。 海量报文&#xff0c;一手掌握&#xff0c;你值得拥有&#xff0c;让我们开始吧&#xff5e; ufw 与 iptables的关系 理论介绍&#xff1a; ufw&#xff08;Uncomplicated Firewall&#xff09;是一个基于iptables的前端工具&#xf…

Python使用Selenium自动实现表单填写之蛇年纪念币蛇钞预约(附源码,源码有注释解析,已测试可用

Python实现纪念币预约自动填写表单 声明:本文只做技术交流,不可用代码为商业用途,文末有源码下载,已测试可用。 Part 1 配置文件改写(源码 有详细的注释说明 读取配置文件,自己组数据库,录入信息 配置文件 Part 2 主函数 每一期的xpath路径都不一样 所以需要提前去网站…

内存管理面试常问

为什么要有虚拟内存&#xff1f; 虚拟内存 如果你是电⼦相关专业的&#xff0c;肯定在⼤学⾥捣⿎过单⽚机。 单⽚机是没有操作系统的&#xff0c;所以每次写完代码&#xff0c;都需要借助⼯具把程序烧录进去&#xff0c;这样程序才能跑起来。 另外&#xff0c; 单⽚机的 CPU …

插入排序⁻⁻⁻⁻直接插入排序希尔排序

引言 所谓的排序&#xff0c;就是使一串记录按照其中的某个或某些关键字的大小&#xff0c;递增或递减的排列起来的操作。 常见的排序算法有&#xff1a; 今天我们主要学习插入排序的直接插入排序和希尔排序。 直接插入排序 什么是直接插入排序&#xff1f; 直接插入排序其…

基于Springboot + Vue开发的飞驰驾校预约学习平台(项目源码 + lw)

一、功能介绍 飞驰驾校预约学习平台包含管理员、教练、用户三个角色以及前后台系统。 主要功能 前台系统功能 首页展示、理论考试、教练信息、教练预约、学习资料、学习视频观看、用户留言、公告信息展示、个人中心信息管理 后台系统功能 管理员或用户登录成功后&#xff0c…

【vivado】时序报告--best时序和worst时序

利用vivado进行开发时&#xff0c;生成best时序报告和worst时序报告。 best时序报告 slow选择min_max&#xff0c;fast选择none。 worst时序报告 fast选择min_max&#xff0c;slow选择none。

深度学习GPU显卡4060ti与4060有什么区别?又与游戏显卡有什么区别?

深度学习GPU显卡4060 Ti与4060的区别 &#xff1a; 性能差异 &#xff1a; 4060 Ti : 4060 Ti通常比4060更强大&#xff0c;具有更多的CUDA核心和更高的显存带宽&#xff0c;因此在计算密集型任务&#xff08;如深度学习训练和推理&#xff09;中表现更好。其显卡核心频率、CUD…