01. 就该这么学并发 - 线程的创建(多姿势)

Java多线程并发编程系列-01 线程基本概念、创建、使用 本文介绍了并发编程中线程的基本概念与使用方式。首先阐述了进程与线程的区别,指出线程是CPU调度的基本单位,而进程是资源分配的单位。接着分析了多线程的优势(提高CPU利用率)和局限性(线程安全问题、切换开销)。文章对比了串行、并行和并发的概念,并详细讨论了同步/异步、阻塞/非阻塞四种组合模式。在实践部分,介绍了三种创建线程的方法:继承Thread类、实现Runnable接口、实现Callable接口配合FutureTask,以及线程池方式。最后解析了Java线程的6种状态(NEW、RUNNABLE、BLOCK 阅读详情

本章开始,咸鱼君将开启一个新的专栏 就该这么学并发 来记录学习Java并发编程的相关内容~

互联网图片,版权归原作者

前言

说到**并发编程,就不得不先说多线程,因为并发的本质就是多线程的处理**

进程和线程

  • 进程 (ps: 每一个程序就是一个进程)
进程指运行中的应用程序,每个程序运行时就会开启一个进程
进程是系统分配资源的最小单位
进程有独立系统资源(进程间的资源是隔离的)
每个进程至少有一个线程

- 线程 (ps: 进程至少有一个线程)

线程依托于进程
线程除了支持本身运行的一点系统资源外(如: 
控制线程运行的线程控制块,保留局部变量和少数参数的栈空间)
不额外拥有独立的资源,但是共享进程的资源
线程也是CPU调度的最小单位

我们眼见为实,右键打开windows系统的任务管理器

image

CPU调度执行策略简介

CPU如何调度进程/线程呢?

CPU依托于**CPU调度算法**来调度,如下

  • RR(Round Robin)
时间片轮转调度算法,每个进程/线程会被分配一个时间片,
在这个时间片的时间段内,允许进程/线程运行
  • FIFO((First In First Out)
先进先出算法,按照进程就绪的先后顺序来使用CPU
  • SCBF(Shortest CPU Burst First)
短进程优先算法,先给每个进程都设置一个优先级,
根据比较优先级来确定下一个执行的进程;
将一些相对短的进程优先级适当提高
  • Virtual RR
虚拟轮转法,时间片轮转法的改进算法
  • PSA(Priority Scheduling Algorithm)
优先级算法,给每一个进程一个优先级,
优先级越高的事件先执行
  • 其它……

看完以上调度算法, 大家留下个

CPU有很多调度算法,并不仅仅只有RR时间片调度

这么个印象就好

因为现在说起线程调度, 很多文章开口就是**时间片调度,可能会造成误解, 认为CPU调度只有RR算法一种, 这显然是不严谨**的.

JVM虚拟机简介

JVM是一个**虚构出来的计算机,是通过在实际的计算机上仿真模拟**各种计算机功能来实现的.

引入Java语言虚拟机后,Java语言在不同平台上运行时不需要重新编译.Java语言使用Java虚拟机屏蔽了与具体平台相关的信息,使得**Java语言只需生成在Java虚拟机上运行的目标代码,就可以在多种平台上不加修改地运行**

简而言之

JVM就是个翻译器,依托于它,java才实现了 “一次编译,多处(平台)运行!”

当然,和C,C++等编译语言不同的点在于,java编译出来的是**字节码文件,也就是“.class”文件,这种文件被JVM所认识,再由JVM来翻译解释成具体平台的可执行文件,而后可被具体平台运行**.

简单的流程关系如下:

java文件(.java)--编译-->(.class)---->(JVM)解释---->(可执行文件)运行

所以

有人说JAVA是编译型语言,也有人说是解释型语言,其实都没什么问题!

线程的生命周期

下面我们进入本章的正题,着重讲解下线程的**生命周期**!

先来张线程生命周期的纲要图,方便大家理解,后续针对每个节点细讲.

图片来自互联网,版权归原作者

线程大致有五种状态

本章, 我们聊聊线程生命周期的第一个状态“新建”.

新建(New)

当线程对象对创建后,即进入了新建状态

- 此时JVM为其分配内存,并初始化其成员变量的值;

- 此时线程对象没有表现出任何线程的动态特征,程序也不会执行线程的线程执行体run();

线程的创建分为

  • 无返回值

  • 有返回值

下面我们一一示例

无返回值的创建方式

  • 继承Thread类
class ExtendsThread extends Thread {
    // 重写run方法
    @Override
    public void run() {
        System.out.println("子线程" + Thread.currentThread().getName() + "正在执行 ");
    }
}

class Test {
    public static void main(String[] args) throws Exception {
        ExtendsThread t = new ExtendsThread();
        t.start();
}

当然,我们也可以简单点,使用**匿名类**的方式创建

class Test {
    public static void main(String[] args) throws Exception {
        Thread t = new Thread(){
               public void run(){
                   System.out.println("Thread Running");
               }  
             };
        t.start();
}
  • 实现Runnable接口
public class ImpRunnableThread implements Runnable {
 //重写run方法 
  @Override
  public void run(){
  log.info("子线程{}正在执行 ",Thread.currentThread().getName());
  }
}

//测试
class Test {
    public void main(String[] args){
        ImpRunnableThread t = new ImpRunnableThread();
        Thread thread = new Thread(t);
        thread.start();
    } 
}

同样,我们可以使用匿名类的方式创建

public class Test {
    public static void main(String[] args) throws Exception {
        Thread t = new Thread(new Runnable(){
            @Override
            public void run() {
                System.out.println("Runnable running");
            }
        });
        t.start();
    }
}

有返回值的创建方式

  • 使用Callable和Future创建线程
public class ImpCallableThread implements Callable {
    //重写call方法
    @Override
    public String call() {
        log.info("子线程{}正在执行 ",Thread.currentThread().getName());
        return "返回值";
    }
}
//测试
class Test {
    public void main(String[] args){
        FutureTask task = new FutureTask(new  ImpCallableThread());
        new Thread(task).run();
        log.info("线程中获取到的返回信息  {} ",task.get());
}

线程池创建线程

其实是比较**推荐大家用线程池**的方式去创建线程的,好处如下

  • 降低资源消耗
通过重复利用已创建的线程降低线程创建和销毁造成的消耗
  • 提高响应速度
当任务到达时,任务可以不需要的等到线程创建就能立即执行
  • 提高线程的可管理性
线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控

关于如何创建线程池,其实Java 已经提供了 Executors,

Java 通过 Executors 提供**四种线程池**,例如:

  • newCachedThreadPool
创建一个可缓存线程池,如果线程池长度超过处理需要,
可灵活回收空闲线程,若无可回收,则新建线程
  • newFixedThreadPool
创建一个定长线程池,可控制线程最大并发数,
超出的线程会在队列中等待
  • newScheduledThreadPool
创建一个定长线程池,支持定时及周期性任务执行
  • newSingleThreadExecutor
创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,
保证所有任务按照指定顺序(FIFO,LIFO,优先级)执行

不过,从**实际开发角度,直接使用Executors返回线程池会有一些问题,所以我们并不推荐以上的方式来创建线程池(阿里内部也是明确规定不允许采用这种方式的**)

原因如下:

  • FixedThreadPool 和 SingleThreadExecutor : 允许请求的队列长度为 Integer.MAX_VALUE,可能堆积大量的请求,从而导致OOM

  • CachedThreadPool 和 ScheduledThreadPool : 允许创建的线程数量为 Integer.MAX_VALUE ,可能会创建大量线程,从而导致OOM

避免使用Executors创建线程池主要是为了避免其中的默认实现,可以改用ThreadPoolExecutor构造方法指定参数

image.png

class Test {
public void main(String[] args){
  ExecutorService executorService = new ThreadPoolExecutor(5,10,10,TimeUnit.SECONDS,new ArrayBlockingQueue<Runnable>(5));
  for (int i = 0; i < 20; i++) {
       executorService.execute(new Runnable() {
       @Override
       public void run() {
               log.info("线程  {}  开始",Thread.currentThread().getName());
         }});
       }
}
}

需要指定**核心线程池的大小、最大线程池的数量、保持存活的时间、等待队列容量的大小**;

在这种情况下一旦提交的线程数超过当前可用的线程数时就会抛出拒绝执行的异常

java.util.concurrent.RejectedExecutionException 

解决方式就是**尽量调大最大线程数**

除了自己定义的**ThreadPool**之外,还可以使用开源库 **apache guava**等,大家自行选择如何使用~

哪种创建线程的方式比较好?

关于这个问题,其实推荐的是

实现Runnable接口

因为**线程池可以有效的管理实现了Runnable接口的线程**,如果线程池满了,新的线程就会排队等候执行,直到线程池空闲出来为止.而如果线程是通过实现Thread子类实现的,这将会复杂一些.

有时我们要同时融合实现Runnable接口和Thread子类两种方式.例如,实现了Thread子类的实例可以执行多个实现了Runnable接口的线程.一个典型的应用就是线程池.

请关注我的订阅号

订阅号.png

ESP32连接OneNet云平台实现多设备联动控制完整示例 通过esp32连接onenet云平台,实现远程设备间的智能联动控制,利用MQTT协议完成数据通信,esp32连接onenet云平台后可高效稳定地上传与下发指令,提升物联网系统响应速度与自动化水平。 阅读详情

相关推荐

【自然语言处理】【聚类】TELL:可解释神经聚类

超越分类的XAI:可解释神经聚类 《XAI Beyond Classification: Interpretable Neural Clustering》 论文地址:https://www.jmlr.org/papers/volume23/19-497/19-497.pdf 一、简介 ​ 本文研究了可解释AI(XAI\text{XAI}XAI)和数据聚类这两个挑战性问题。第一个问题是如何设计一种具有固定可解释性的神经网络,而不是给出一个黑盒模型的事后解释。第二个问题是,使用可微分神经网络来实现离散的k-me

bqw的博客 4134

创建线程的三种方法及并发并行的简单介绍

并发与并行 并发编程的目的是为了让程序运行得更快,但是,并不是启动更多的线程就能让程序最大限度地并发执行。 并发与并行的区别:并发是指多个线程操作同一个资源,不是同时执行,而是交替执行,单核CPU也支持多线程执行代码,CPU通过给每个线程分配CPU时间片来实现这个机制。时间片是CPU分配给各个线程的时间,因为时间片非常短,所以CPU通过不停地切换线程执行,让我们感觉多个线程是同时执行的,时...

weixin_44048140的博客 787

在Mac上搭建本地AI工作流:Dify与DeepSeek的完美结合

本文介绍了在Mac上搭建本地AI工作流的方法,结合Dify平台和DeepSeek模型。Dify是一个开源的大语言模型应用开发平台,支持可视化AI应用开发。部署步骤包括:1)安装Homebrew和Docker;2)克隆Dify代码库;3)配置环境变量并启动服务。同时,使用Ollama工具本地部署DeepSeek模型,将其集成到Dify中创建聊天助手。通过配置模型接口和新建应用,用户可以在本地环境中实现AI对话功能。这种方案既保证了数据隐私,又提供了灵活的AI应用开发能力。

Linda的自动化测试之旅 1535

Linux线程——线程创建和基本使用(多线程并发)

1.线程的概念与实现方式 1.1 线程的概念 概念:线程是进程内部的一条执行序列或执行路径,一个进程可以包含多条线程。线程是进行资源调度和分配的基本单位 。 (1)每个进程至少有一条执行路径,所以一个进程至少有一个进程。 (2)每个进程都有一个主线程。 1.2 线程的实现方式 在操作系统中,线程的实现有以下三种方式: (1)用户级线程:由线程库中的代码进行管理,处理 ,销毁。用户自己创建的多线程,即多个处理路径,无法使用多处理器的资源,在内核眼里就只是一条路径。 (2)内核级线程:由内核直接创建、直接管理

yi_chengyu的博客 2万+

DISM错误87详解:RestoreHealth选项无法识别的修复方法

DISM(部署映像服务和管理工具)是Windows系统维护与修复的核心命令行工具,常与SFC(系统文件检查器)配合使用,用于扫描和修复组件存储损坏、系统文件缺失等问题。在执行系统健康检查时,用户常会遭遇错误87,提示“未在此上下文中识别出restorehealth选项”。该错误的本质并非工具损坏,而是命令参数结构不符合DISM的语法解析规则,或当前系统环境(如Windows 7、WinRE/PE、32位环境)不支持该参数。理解DISM的命令层级、参数挂载关系以及运行上下文,是精准排除故障的前提。通过核对标准

weixin_34116482的博客 463

字符串尾部空格的迷思:深入解析 ABAP 隐式转换规则与 `strlen` 意外结果

看似简单的strlen之谜,背后实则是 ABAP 隐式转换的一整套严谨规则。只要开发者在赋值、输出、接口映射等关键节点建立“尾部空格意识”,辅以CONVCONDENSE等显式手段,就能有效杜绝多余空格引发的链式故障。希望本文的拆解与案例,能让你在面对下一个“异常长度”时,从容而笃定地给出正确答案。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 430

【线程】线程创建 | 理解线程并发 (1)

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg); //thread: 接收创建的线程的 ID //attr: 指定线程的属性 (一般传空) //start_routine: 指定线程函数 //arg: 给线程函数传递的参数 //成功返回 0, 失败返回错误码 ```...

weixin_52958292的博客 399

gseapy python包GO、KEGG富集(注释)分析

文档案例参考:https://gseapy.readthedocs.io/en/latest/gseapy_example.html#Over-representation-analysis-by-Enrichr-web-services安装:建议安装最新版(这里安装的1.04):https://github.com/zqfang/GSEApy/releases。

weixin_42357472的博客 3610

第三章、 核心1:实现多线程的正确姿势

1、实现多线程的方法是1种,2种还是4种? Oracle官网的文档是如何写的? 方法一:实现Runnable接口 方法二:继承Thread类 1.1 实现示例 实现Runnable接口 /** * RunnableStyle * * @author venlenter * @Description: 用Runnable方式创建线程 * @since unknown, 2020-03-23 */ public class RunnableStyle implements Runnable

Coder 279

Vue2 - 详细实现安装西瓜视频 xgplayer 插件详细配置及使用教程,利用西瓜视频播放器播放 mp4、flv、hls 格式视频文件及视频推流(直播或监控摄像头画面),支持移动端H5及PC网站!

vue2,nuxt2,西瓜视频,xgplayer,插件组件,xgplayer-hls,xgplayer-flv,xgplayer-mp4,播放视频点播和直播视频流,自定义播放器样式,截屏,监控视频,vue使用西瓜播放器播放flv、hls、mp4视频,截屏按钮,直播流,报错,黑屏,加载失败,苹果ios不兼容,重连,怎么改样式,很卡,详细教程,监控实时播放推流,倍速播放,在线flv在线推流地址,HLS播放,vue西瓜播放器,vue如何使用西瓜视频插件做直播推流回流,视频点播,flv在线视频流播放,截图功能,利用

🏆 前端领域优质创作者 1万+

泰凌微8258入门教程 环境篇④——开发板+烧录器 8258mesh新手套件购买

工欲善其事,必先利其器。 淘宝链接:https://item.taobao.com/item.htm?

4128

多线程(一):创建线程和线程的常用方法

一:为什么要学多线程 应付面试 :多线程几乎是面试中必问的题,所以掌握一定的基础知识是必须的。 了解并发编程:实际工作中很少写多线程的代码,这部分代码一般都被人封装起来了,在业务中使用多线程的机会也不是很多(看具体项目),但是作为一个高级程序员如果不会多线程是说不过去的。 二:进程与线程 进程 进程是资源(CPU、内存等)分配的基本单位,它是程序执行时的一个实例。程序运行时系统...

人不风流枉少年 24万+

FPGA经验谈系列文章——3、逻辑级数

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 Xilinx FPGA开发tips系列——前言一、pandas是什么?二、使用步骤1.引入库2.读入数据总结 前言 提示:这里可以添加本文要记录的大概内容: 例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。 提示:以下是本篇文章正文内容,下面案例可供参考 一、pandas是什么? 示例:pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的

gzy0506的博客 1万+

Thread多线程(创建,方法,安全,通信,线程池,并发,并行,线程的生命周期)【全详解】

线程是什么?线程(Thread)是一个程序内部的一条执行流程。程序中如果只有一条执行流程,那这个程序就是单线程的程序。多线程是什么?多线程是指从软硬件上实现的多条执行流程的技术(多条线程由CPU负责调度执行)。

qq_1424674116的博客 4772

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

01、多线程高并发基础

本篇文章主要讲一些和线程,进程,的基础常识问题。

qq_21451945的博客 925

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

JUC并发编程01 - 进程与线程/创建线程

进程与线程概述,并发与并行,同步与异步,线程进程对比(IPC,进程通信方式...),创建线程(Thread,Runnable,Callable)

南清在coding的博客 759

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

多线程学习笔记01线程、进程、多线程与线程创建

多线程学习笔记01线程、进程、多线程与线程创建。

2501_90425057的博客 1667

JUC并发编程01——进程,线程(详解),并发和并行

进程:程序是静止的,进程实体的运行过程就是进程,是系统进行资源分配的基本单位进程的特征:并发性、异步性、动态性、独立性、结构性线程:线程是属于进程的,是一个基本的 CPU 执行单元,是程序执行流的最小单元。线程是进程中的一个实体,是系统独立调度的基本单位,线程本身不拥有系统资源,只拥有一点在运行中必不可少的资源,与同属一个进程的其他线程共享进程所拥有的全部资源关系:一个进程可以包含多个线程,这就是多线程,比如看视频是进程,图画、声音、广告等就是多个线程。

qq_59708493的博客 1266

Java并发01:进程、线程、并发、并行、多线程、线程安全、死锁、并发优缺点

[超级链接:Java并发学习系列-绪论] 本章主要对Java并发(Concurrent)相关的概念进行说明。 1.进程(Process)与线程(Thread) 进程是系统资源分配的最小单元。线程是CPU调度的最小单元。 一个 进程至少包含一个线程,可以包含多个线程。这些线程共享这个进程的资源。 每个线程都拥有独立的运行栈和程序计数器,线程切换开销小。 多进程指的是操作系统同时运行多个程...

韩超的博客 (hanchao5272) 3347

java多线程并发之旅-01-多线程并发教程概览

本系列学习目的 提升对于 java 多线程的理解,要学会横向对比学习,多看些文章。 目前大部分的文章都是止步于创建和常见的类,本系列重在实践,参考书籍《java 并发编程实战》《Java并发编程的艺术》 后续原理参考《深入理解并行编程》。 对于 java 多线程的基础知识,参考 Java Thread 小结 经典书籍《图解 Java 多线程设计模式》 系列学习笔记。 对于 jvm 相关知识不用重复...

1万+

【线程探秘】Java并发艺术

科大讯飞高级架构师十余年经验总结!自顶向下详解Java线程实现原理与实践《一本书讲透Java线程:原理与实践》推文赠书

优快云站内信: https://i.youkuaiyun.com/#/msg/chat/qyj19920704 2万+

Java并发 day01进程和线程 、并行和并发、 java线程

Java并发 day01进程和线程 、并行和并发、 java线程

weixin_44504809的博客 1434

【QT进阶】Qt线程与并发之创建线程的三种方法(超详细介绍)

【QT进阶】Qt线程与并发之创建线程的三种方法

LF__plus的博客 4428

Python的线程01 认识线程

正式的Python专栏第41篇,同学站住,别错过这个从0开始的文章! 前面文章写了很多,都是比较基础的。 这篇开始我们将进入中级编程。处理更加复杂事情。比如本文的线程,咱们先从基础知识入手! 什么是线程? 我们知道工人都是同时在工厂工作,复制各自的工作的。他们就是一个一个独立运行的单位! 线程也是类似这样的一个独立的运行单位,多线程,就是多个独立的运行单位,同时执行同样的事情。 简单这样理解,后面会进行对比。 threading.Thread 类是Python中的线程类,它封装了线程的信息和一些同用的.

持续学习持续开发,我是雷学委! 2491

Java并发编程-01-线程的创建和线程信息获取

一、创建线程的方式 1、继承Thread类,覆盖run方法 2、实现Runnable接口,创建Thread类的实例,通过构造方法实现 3、Runnable接口只有一个抽象的run方法,也就是说Runnable接口本身不支持多线程 public interface Runnable { /** * When an object implementing interf

我自倾怀,君且随意 1301

【并发技术01】传统线程技术中创建线程的两种方式

传统的线程技术中有两种创建线程的方式:一是继承Thread类,并重写run()方法;二是实现Runnable接口,覆盖接口中的run()方法,并把Runnable接口的实现扔给Thread。这两种方式大部分人可能都知道,但是为什么这样玩就可以呢?下面我们来详细分析一下这两种方法的来龙去脉。 1. 揭秘Thread中run() 上面我们看到这两种方式都跟run()方法有...

华为云官方博客 1357
上一篇: 39. 从零开始学springboot-好用的开源工具类
下一篇: IP 如何存储?
码哥说
博客等级 码龄8年 5645粉丝 172原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码哥说

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值