JUC并发编程基础(包含线程概念,状态等具体实现)

一.JUC并发编程基础

1. 并行与并发

1.1 并发:

  1. 是在同一实体上的多个事件
  2. 是在一台处理器上"同时处理多个任务"
  3. 同一时刻,其实是只有一个事件在发生.

即多个线程抢占同一个资源.
在这里插入图片描述

1.2 并行

  1. 是在不同实体上的多个事件
  2. 是在多台处理器上同时处理多个任务
  3. 同一时刻,大家都在做事情.你做你的,我做我的.

即多个线程同时执行.

在这里插入图片描述

2. 进程,线程,管程

2.1 进程

在系统中运行的一个应用程序就是一个进程,每一个进程都有它自己的内存空间和系统资源.

2.2 线程

也被叫做轻量级进程,在同一个进程内会有1个或多个线程,是大多数操作系统进行时序调度的基本单元

2.3 管程

也被称为Monitor(监视器),也就是平时我们所说的锁.

3. 线程启动的三种方式

3.1 继承Thread类.重写run方法

继承重写

    public class MyThread extends Thread {
        @Override
        public void run() {
            for (int i = 0; i < 100; i++) {
                System.out.println(Thread.currentThread().getName() + " " + i);
            }
        }
    }

执行

    public class ExtendThreadMain {
        public static void main(String[] args) {
            MyThread myThread = new MyThread();
            myThread.start();
        }
    }

注意:启动线程是调用父类的start方法,而不是直接去调用run方法.

3.2 实现Runable接口

实现重写

    public class MyThread implements Runnable{
        @Override
        public void run() {
            for(int i=0;i<10;i++){
                System.out.println(Thread.currentThread().getName()+":"+i);
            }
        }
    }
    

主函数启动线程

    public class RunnableThreadMain {
        public static void main(String[] args) {
            MyThread myThread = new MyThread();
    
            Thread t1 = new Thread(myThread);
    
            t1.start();
        }
    }
    

当然我们还有另外一种写法

注意到Thread的构造方法的参数有
在这里插入图片描述

里面存在一个Runnable参数和一个线程名的两个参数的方法.熟悉静态内部类或者Lamba表达式的应该了解,这里完全可以利用这种特性来启动线程,所以我们可以这样改写.


    public class RunnableThreadMain {
        public static void main(String[] args) {
    //        MyThread myThread = new MyThread();
    //        Thread t1 = new Thread(myThread);
    
            Thread t1 = new Thread(() -> {
                for (int i = 0; i < 10; i++) {
                    System.out.println(Thread.currentThread().getName() + " " + i);
                }
            }, "t1");
    
            t1.start();
        }
    }
    

3.3 实现Callable接口

实现重写call方法(其实也就跟上述两个的run方法的作用一样)

    /**
     * 这里的泛型指的是call方法的返回值
     */
    public class MyThread implements Callable<Integer> {
    
        @Override
        public Integer call() throws Exception {
            int sum = 0;
            for (int i = 0; i < 100; i++) {
                sum+=i;
            }
            return sum;
        }
    }

主函数调度,这里与其他两种实现不同的是,可以有返回值,这里引用了FutureTask接口来接收这个值

    public class CallableThreadMain {
        public static void main(String[] args) throws ExecutionException, InterruptedException {
    
            MyThread myThread = new MyThread();
    
            FutureTask<Integer> futureTask = new FutureTask<>(myThread);
    
            Thread t1 = new Thread(futureTask);
    
            t1.start();
    
            Integer sum = futureTask.get();
            System.out.println("sum = " + sum);
        }
    }
    

注意:get方法时,方法会阻塞,直到这个线程执行完毕有返回值,代码才会往下进行.

4. 守护线程

守护线程

  • 守护线程是一种特殊的线程,它并不属于用户线程,也不受用户线程的控制,但它却有着特殊的重要性。
  • 守护线程的主要目的是为其他非守护线程提供服务。当所有的用户线程都结束时,守护线程也会随之结束
  • 守护线程的创建方式是在启动线程时调用Thread.setDaemon(true)方法,该方法将线程设置为守护线程。
  • 判断当前线程是否为守护线程调用 Thread.currentThread().isDaemon()方法,true为是,false为不是

守护线程的退出条件是:

  1. 所有用户线程都结束;
  2. 调用了Thread.stop()方法;
  3. 调用了Runtime.exit()方法。

注意:

  1. 守护线程只能有一个,一个JVM中只能有一个守护线程;
  2. 守护线程不能执行用户线程的run()方法,因为它没有用户线程可执行;
  3. 守护线程的优先级比较低,它只会在JVM中运行,不会影响到其他线程的运行;
  4. 守护线程的异常处理方式和非守护线程相同。
    public class ProtectThread {
        public static void main(String[] args) {
            //创建一个线程
            Thread t1 = new Thread(() -> {
                System.out.println(Thread.currentThread().getName() + ": " +
                        (Thread.currentThread().isDaemon() ? " 守护线程" : "用户线程"));
                while (true) {
                }
            },"t1");
            t1.setDaemon(true);//设置为守护线程
            t1.start();
            
            System.out.println(Thread.currentThread().getName() + ": " +
                    (Thread.currentThread().isDaemon() ? " 守护线程" : "主线程"));
        }
    }

5. windows,linux下查看和杀死进程

5.1windows

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

  • tasklist 查看进程
    在这里插入图片描述

  • taskkill 杀死进程

    • 通常带两个参数 /F 强制杀死 /PID 进程id

5.2 linux

  • ps -ef 查看所有进程
    在这里插入图片描述

  • ps -fT -p 查看某个进程(PID)的所有线程

在这里插入图片描述

  • kill 杀死进程
  • top按大写H切换是否显示线程

动态展示所有进程占用cpu的情况
在这里插入图片描述

  • top -H -p 查看某个进程(PID)的所有线程

5.3 查看Java的进程

  • jps 命令查看所有 Java进程

  • jstack 查看某个Java进程 (PID) 的所有线程状态.
    在这里插入图片描述

  • jconsole 来查看某个Java进程中线程的运行情况(图形界面)
    在这里插入图片描述

6. 线程运行原理

我们知道JVM虚拟机中有栈和堆两块内存区域.

而每一个线程都有属于自己的栈区,每个线程直接的栈互不干扰,线程中每一个方法都是一个栈帧.

看如下这段代码的调度过程:
在这里插入图片描述

我们再通过一幅图来理解

在这里插入图片描述

7. 线程的上下文切换

有些时候由于一些原因,当线程在执行时,cpu被其他线程抢占到也就是说存在线程之间的切换的过程,我们称为上下文切换.

哪些原因会导致线程上下文切换呢

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

当上下文切换时,需要由操作系统去保存当前线程的状态,也就是记录其中的一些变量啊,执行到哪一步啦,并恢复另一个线程的状态,Java中对应的概念就是程序计数器,它的作用是记住下一条JVM指令的执行地址,是线程自己私有的

  • 状态包括程序计数器,虚拟机栈中每个栈帧的信息,如局部变量,操作数栈,返回地址

注意:频繁的上下文切换会影响性能.

8. 线程的几种状态

8.1 五种(来源于操作系统)

在这里插入图片描述

  • 初始状态: 相当于我们刚刚new出来一个线程对象.仅是在语言层面创建了线程对象,还并未与操作系统线程相关联.
  • 可运行状态(就绪状态) : 指该线程已经被创建(与操作系统线程关联),可以由CPU调度执行.也就是都准备去抢占cpu啦,如果抢到了就会进入运行状态
  • 运行状态: 指获取了CPU时间片运行中的状态.
    • 当CPU时间片用完会从运行状态转换至就绪状态, 会导致线程的上下文切换
  • 阻塞状态
    • 如果调用了阻塞的API,例如BIO(同步阻塞IO)读写文件,这时该线程不会用到CPU,会导致线程上下文切换,进入阻塞状态.
    • 等BIO操作完毕,会由操作系统唤醒阻塞的线程,转换至可运行状态.
    • 与可运行状态的区别是,对阻塞状态的线程来说只要它们一直不唤醒,调度器一直不会考虑调度它们.

可以这样理解: 好比去上厕所,你抢到厕所的使用权啦,但是突然你又不想上啦,想起还有其他事情要做,总不能占着茅坑不拉屎叭,所以cpu,也就是厕所,你得离开这里,这个时候你去干其他的事都可以,等你忙完又想上厕所啦,这个时候又和别人一样需要有机会才能抢到厕所的使用权,也就是重新回到就绪状态.

  • 终止状态: 表示线程已经执行完毕,生命周期已经结束,不会在转换为其他状态.也就是代码执行完毕,没有循环的包裹,执行完就会进入终止状态.

8.2 六种(Java层面)

我们来查看Thread类当中的一个枚举类State
在这里插入图片描述
所以一共有六种状态,其具体为
在这里插入图片描述

  • NEW 线程刚被创建,但是还没有调用start()方法
  • RUNNABLE当调用了start()方法之后.

注意: JavaAPI层面的RUNNABLE状态涵盖了操作系统层面的可运行状态(就绪状态),运行状态,阻塞状态(由于BIO导致的线程阻塞,在Java里无法区别,仍然认为是可运行,也就是RUNNABLEZ状态)

  • BLOCKED 可以理解为抢占锁时未抢到,造成阻塞等待
  • WAITING 等待别的线程执行结束
  • TIMED_WATING 有时间的等待,也就是对应Thread.sleep();
  • TERMINATED 当线程代码运行结束
8.2.1 代码实现每种状态
  • NEW (创建线程不开始)
    在这里插入图片描述

  • RUNNABLE(就绪,运行,阻塞(操作系统的层面例如IO流时))
    在这里插入图片描述

  • TERMINATED (代码执行完毕就进入此状态)
    在这里插入图片描述

  • TIMED_WATING (睡眠时进入)
    在这里插入图片描述

  • WAITING(利用join方法,使线程2等待线程1执行完毕,此时状态为WAITING)
    在这里插入图片描述

  • BLOCKED(阻塞,抢占锁失败,阻塞等待)
    在这里插入图片描述

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

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

相关文章

【码银送书第二十二期】《Python数据分析从入门到精通(第2版)》

&#x1f490;大家好&#xff01;我是码银~&#xff0c;欢迎关注&#x1f490;&#xff1a; CSDN&#xff1a;码银 公众号&#xff1a;码银学编程 前言 &#x1f340;丛书说明&#xff1a;“软件开发视频大讲堂‘’丛书第1版于2008年8月出版&#xff0c;因其编写细腻、易学实用…

ython 使用 cx_Freeze 打包,不想要打包文件中能直接看到依赖的代码,如何处理

背景&#xff1a;因为使用 cx_Freeze 打包时&#xff0c;添加需要依赖的文件 cx_Freeze 是一个用于将 Python 程序打包成独立可执行文件的工具&#xff0c;支持多个平台。当你需要打包包含多个 .py 文件的项目时&#xff0c;你可以通过编写一个 setup.py 文件来指定哪些模块应…

免杀笔记 ----> ShellCode Loader !!!

学了那么久的前置知识&#xff0c;终于到了能上线的地方了&#xff01;&#xff01;&#xff01; 不过这里还没到免杀的部分&#xff0c;距离bypass一众的杀毒软件还有很长的路要走&#xff01;&#xff01; 目录 1.ShellCode 2.ShellCode Loader的概念 3.可读可写可…

【邀请函】相约CommunityOverCode Asia 2024,共探Flink、Paimon、Celeborn开源新境界!

CommunityOverCode是由Apache软件基金会&#xff08;ASF&#xff09;主办的一系列全球性会议&#xff0c;旨在促进开源技术的发展和社区参与。自1998年以来&#xff0c;ApacheCon一直是这一系列活动的核心&#xff0c;吸引了不同背景和技术层级的参与者&#xff0c;关注于“明天…

C++11 shared_ptr---面试常考

shared_ptr简介 共享对其所指堆内存空间的所有权&#xff0c;当最后⼀个指涉到该对象的shared_ptr不再指向他时&#xff0c;shared_ptr会⾃动析构所指对象如何判断⾃⼰是否指涉到该资源的最后⼀个&#xff1f;《引⽤计数》 shared_ptr构造函数&#xff0c;使引⽤计数析构函数&…

应用了网络变压器的PC网卡连接转换器后不好连网,有掉线现象,但外接路由器无问题,可能是什么原因?

Hqst盈盛&#xff08;华强盛&#xff09;电子导读&#xff1a;今天分享的是应用了网络变压器的PC网卡连接转换器后不好连网&#xff0c;有掉线现象&#xff0c;但外接路由器无问题&#xff0c;可能是什么原因呢&#xff1f;如何解决呢&#xff1f; 首先&#xff0c;我们要了解传…

Java后端开发(十二)-- 未配置 Spring Boot 配置注解处理器

目录 1. 错误表现形式 2. 解决方式 1. 错误表现形式 2. 解决方式 在 Spring Boot 应用程序中,通常使用 @ConfigurationProperties 注解来将配置文件中的属性绑定到 Java 对象中。如果没有配置 Spring Boot 配置注解处理器,那么这些注解将无法自动处理和加载。 …

清空flowable的表定义的相关表

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码&#xff1a; https://gitee.com/nbacheng/ruoyi-nbcio 演示地址&#xff1a;RuoYi-Nbcio后台管理系统 http://218.75.87.38:9666/ 更多nbcio-boot功能请看演示系统 gitee源代码地址 后端代码&#xff1a; h…

qt 如果把像素点数据变成一个图片

1.概要 图像的本质是什么&#xff0c;就是一个个的像素点&#xff0c;对与显示器来说就是一个二维数组。无论多复杂的图片&#xff0c;对于显示器来说就是一个二维数组。 2.代码 #include "widget.h"#include <QApplication> #include <QImage> #incl…

兴业小课堂|什么是法拍房助拍机构?如何挑选靠谱的助拍机构?

随着法拍房市场的不断发展和扩大 使法拍房数量的增加 其交易的复杂性和专业性需求也日益凸显 这促使了专门机构的出现来满足市场需求 法拍房助拍机构存在的原因主要有以下几点&#xff1a; 1.专业知识和经验&#xff1a; 法拍房的交易流程相对复杂&#xff0c;涉及到法律法…

对标 GPT-4o 的开源实时语音多模态模型:Moshi

是由法国的 AI 实验室 Kyutai 推出的实时语音多模态模型&#xff0c;支持听、说、看&#xff0c;最关键的是你现在就可以在浏览器中使用&#xff0c;如果这个链接延迟高&#xff0c;可以试试这个, 无需输入邮箱&#xff0c;点击 Join queue 即可。 简单体验了下&#xff0c;比…

Perplexity: 推出 ProSearch 的新版本

Perplexity 更新了 ProSearch 功能&#xff0c;支持多步推理、高级数学和编程能力&#xff0c;比起快速搜索&#xff0c;提供了更深入、全面的搜索&#xff0c;以及详尽报告和分析。 白嫖用户每 4 个小时可免费使用 5 次&#xff0c;Pro 用户几乎无限制。

ChatGPT:SpringBoot解决跨域问题方法-手动设置请求头

ChatGPT&#xff1a;SpringBoot解决跨域问题方法-手动设置请求头 这里的设置响应头是为了发送请求方还是接收请求方 设置响应头是为了发送请求方。具体来说&#xff0c;添加 Access-Control-Allow-Origin 头部是为了告诉浏览器&#xff0c;哪些域名可以访问资源。当设置为 * 时…

二百四十二、Hive——Hive的动态分区表出现day=__HIVE_DEFAULT_PARTITION__分区

一、目的 Hive的DWD层动态分区表的分区出现day__HIVE_DEFAULT_PARTITION__&#xff0c;有点懵&#xff0c;而且表中数据的day字段也显示__HIVE_DEFAULT_PARTITION__ 1、DWD层动态分区表的分区 __HIVE_DEFAULT_PARTITION__ 2、DWD层分区字段day数据 __HIVE_DEFAULT_PARTITION…

【中项第三版】系统集成项目管理工程师 | 第 4 章 信息系统架构① | 4.1-4.2

前言 第4章对应的内容选择题和案例分析都会进行考查&#xff0c;这一章节属于技术相关的内容&#xff0c;学习要以教材为准。本章分值预计在4-5分。 目录 4.1 架构基础 4.1.1 指导思想 4.1.2 设计原则 4.1.3 建设目标 4.1.4 总体框架 4.2 系统架构 4.2.1 架构定义 4.…

通义灵码入选 2024 世界人工智能大会最高荣誉「镇馆之宝」

7 月 4 日&#xff0c;2024 上海世界人工智能大会正式开幕&#xff0c;并揭晓了今年的「镇馆之宝」名单&#xff0c;通义灵码入选&#xff0c;是首个入围该名单的 AI 编程助手。 镇馆之宝是世界人工智能大会展览的最高荣誉&#xff0c;从科技含量、市场前景、创新性以及社会经济…

pip install包出现哈希错误解决

如图&#xff0c;当遇到此类错误时&#xff0c;多半是连接不稳定导致的校验失败。我们可以在PC端&#xff0c;或Ubuntu通过浏览器下载.whl安装文件&#xff1a;直接复制报错信息中的网址到浏览器即可弹出下载窗口。

Vue3重构案例(使用vue3的语法重构element的button组件)

这篇文章紧接的上一篇文章&#xff0c;上篇文章是对给element的button组件写了一个单元测试&#xff0c;这篇文章是使用vue3的语法进行重构&#xff0c;这里说一下单元测试和重构的联系&#xff0c;当你给组件写了单元测试之后&#xff0c;重构会减少你很多的debug时间&#xf…

Transformer和Mamba强强结合!最新混合架构全面开源,推理速度狂飙8倍

最近发现&#xff0c;将Mamba和Transformer模块混合使用&#xff0c;效果会比单独使用好很多&#xff0c;这是因为该方法结合了Mamba的长序列处理能力和Transformer的建模能力&#xff0c;可以显著提升计算效率和模型性能。 典型案例如大名鼎鼎的Jamba&#xff1a;Jamba利用Tr…

【Unity小知识】UnityEngine.UI程序集丢失的问题

问题表现 先来说一下问题的表现&#xff0c;今天在开发的时候工程突然出现了报错&#xff0c;编辑器提示UnityEngine.UI缺少程序集引用。 问题分析与解决&#xff08;一&#xff09; 既然是程序集缺失&#xff0c;我们首先查看一下工程项目是否引用了程序集。在项目引用中查找一…