Java多线程编程基础
目录
编写第一个多线程程序
1. 方式一 : 继承Thread类, 重写run方法
2. 方式二: 实现Runnable接口, 重写run方法
3. 方式三: 使用Lambda表达式
[匿名内部类]
[Lambda表达式]
在上个文章中, 我们了解了进程和线程的相关概念. 那么, 在Java中, 我们如何进行多线程编程呢?
线程本身是操作系统的一个概念, 操作系统提供一个线程的API, 供程序员调用. 不同的操作系统线程的API是不同的 (Windows的线程API和Linux的线程API差异很大). 但是JVM将不同的系统线程的API都封装好了, 所以我门在不同系统上进行Java的多线程编程时, 不需要关注系统原生的API, 只需要掌握Java这一套API就可以了.
在Java中, Thread类就负责完成多线程的相关开发.
编写第一个多线程程序
我们有多种方式来进行多线程编程.
1. 方式一 : 继承Thread类, 重写run方法
(1) 步骤一: 创建一个线程类

[注]: 这里不需要对Thread进行导包操作, 因为Thread是java.lang包中的类, 默认已经导入.
上述代码, 就创建了一个线程类(MyThread类) 继承自Thread类. 类里重写了run()方法. (run()方法是Runnable接口中定义的一个方法, 用来指定线程要执行的任务, Thread类实现了run方法, 我们定义的MyThread类继承自Thread, 自然需要重写run方法, 来制定我们当前这个线程需要完成什么任务)
(2) 步骤二: 启动线程

观察运行结果, 我们可以看到, 现在控制台上正在循环打印"hello thread", 代表我们创建的MyThread线程启动了. 这里涉及到一个方法start(), 这个方法的作用就是启动线程.
[注]: 通过上述代码, 我们看到, main方法中并没有调用run()方法, 但是程序确实执行力main方法里面的内容. 像这种, 我们手动定义但没有手动调用, 被系统自动调用执行的方法, 叫做"回调函数"(Callback Function)
接下来我们整体看这个代码:
class MyThread extends Thread {@Overridepublic void run() {// 这里写的代码, 就是即将创建出的线程, 要执行的逻辑.while (true) {System.out.println("hello thread");// 该线程需要完成的任务: 循环打印"hello thread".}}
}public class Demo1 {public static void main(String[] args) {MyThread t = new MyThread();t.start(); // 这一步就创建了一个线程}
}
上述代码实际上就是一个进程. 因为调用了main方法, 所以该进程中还有一个执行main方法的线程, 就叫做"主线程". 我们之前说过, 一个进程至少包含一个线程, 这个线程就是主线程.
主线程和t线程会并发/并行地在CPU上调度执行. 宏观表现就是交替打印主线程和t线程中的任务.
class MyThread extends Thread { //创建一个线程类@Overridepublic void run() {// 这里写的代码, 就是即将创建出的线程, 要执行的逻辑.while (true) {System.out.println("hello thread");// 该线程需要完成的任务: 循环打印"hello thread".}}
}public class Demo1 {public static void main(String[] args) {MyThread t = new MyThread(); //实例化一个新线程t.start(); //启动这个线程while (true) {System.out.println("hello main");// 主线程要完成的任务: 循环打印"hello main".}}
}

从运行结果来看, 主线程和t线程的任务交替打印. 那么多个线程之间, 谁先去CPU上调度执行, 谁后去CPU上调度执行, 这个顺序是不确定的, 取决于操作系统的内核. 并且, 我们把这种执行方式叫做"抢占式执行".
* 使用匿名内部类来实现方式一

上述红框框住的代码, 就使用了匿名内部类. 这部分代码完成了3件事: (1) 定义了一个匿名内部类, 这个类一定是Thread的子类. (2) 在这个类内部重写了run方法. (3) 创建了一个类的实例, 并且赋给了引用t.
2. 方式二: 实现Runnable接口, 重写run方法
方式一中, 我们的MyThread类是继承自Thread类的, 而Thread类又实现了Runnable接口. 那么我们能不能直接实现Runnable接口呢? 那当然是可以的.
(1) 步骤一: 创建一个MyRunnable类, 实现Runnable接口

(2) 步骤二: 实例化一个MyRunnable类的对象, 并用这个对象实例化一个新线程.
整体代码如下:
class MyRunnable implements Runnable {@Overridepublic void run() {while (true) {System.out.println("hello thread");// 该线程需要完成的任务: 循环打印"hello thread".}}
}
public class Demo2 {public static void main(String[] args) {MyRunnable myRunnable = new MyRunnable(); //实例化一个MyRunnable类的对象Thread t = new Thread(myRunnable); // 用myRunnable实例化一个新线程t.start();while (true) {System.out.println("hello main");// 主线程需要完成的任务: 循环打印"hello main".}}
}
* 使用匿名内部类来实现方式二:
public class Demo4 {public static void main(String[] args) {
// Runnable runnable = new Runnable(){
// @Override
// public void run() {
// while (true) {
// System.out.println("hello thread");
// }
// }
// };
// Thread t = new Thread(runnable);
// // 上述代码还是比较繁琐, 我们可以再嵌套一层匿名内部类Thread t = new Thread(new Runnable(){@Overridepublic void run() {while (true) {System.out.println("hello thread");}}});// 嵌套两层匿名内部类 实例化出一个线程对象t.start(); //启动线程}
}
3. 方式三: 使用Lambda表达式
public class Demo5 {public static void main(String[] args) {Thread t = new Thread(() -> {while (true) {System.out.println("hello thread");}}); // Lambda表达式: ()代表函数的形参列表为空; {}前面是空的,代表函数没有返回值, {}里面是方法体.}
}
( )内为空代表函数的形参列表为空; { }前面是空的,代表函数没有返回值, { }里面是方法体.
[匿名内部类]
匿名内部类(Anonymous Inner Class)是一种没有名字的内部类,通常用于创建那些只需要使用一次的类实例。匿名内部类可以继承一个类或者实现一个接口,并且可以在创建时立即进行实例化和使用。
[注]: 匿名内部类一般是"一次性使用"的类, 用完一次之后就不再使用了.
匿名内部类可以访问外部类的成员变量和方法,包括私有成员。
匿名内部类只能用于创建一个类的实例,不能用于创建多个实例。
[Lambda表达式]
Lambda表达式其实就是一个"函数式接口"产生的"匿名内部类", 实质上还是一种匿名内部类. Lambda 表达式通常用于实现函数式接口(Functional Interface),这是一个只有一个抽象方法的接口。例如,Runnable 接口只有一个 run 方法,因此可以用 Lambda 表达式来实现。
本篇文章主要讨论了如何写好你的第一个多线程程序, 快去试试吧~~
相关文章:
Java多线程编程基础
目录 编写第一个多线程程序 1. 方式一 : 继承Thread类, 重写run方法 2. 方式二: 实现Runnable接口, 重写run方法 3. 方式三: 使用Lambda表达式 [匿名内部类] [Lambda表达式] 在上个文章中, 我们了解了进程和线程的相关概念. 那么, 在Java中, 我们如何进行多线程编程呢? …...
刷代随有感(134):单调栈——下一个更大元素I(难点涉及哈希表与单调栈的结合)
单调栈处理的是下标! 题干: 代码: class Solution { public:vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {stack<int>ddst;unordered_map<int,int>umap;vector<int…...
Linux云计算 |【第五阶段】CLOUD-DAY5
主要内容: 容器的镜像编排,commit简单镜像创建,Dockerfile制作服务镜像(语法、创建镜像)、创建复杂镜像(Docker微服务架构、示例:NGINXPHP)、私有仓库 一、简单镜像创建 1、自定义…...
被上传文件于后端的命名策略
上一篇博客我们了解了前端上传的文件资源应该存放在后端项目中的什么位置,那么随之而来的另一个问题——我们应该如何为上传的文件命名呢?往往直接采用原文件名并不稳妥,会导致命名冲突、文件冲突、数据库管理冲突等多种问题,下面…...
哈希表 算法专题
哈希表简介 是什么 存储数据的容器有啥用? "快速"查找某个元素什么时候用哈希表 频繁地查找某个数(有序用二分)怎么用哈希表 容器用数组模拟 字符串中的字符 范围比较小的数 一. 两数之和 两数之和 class Solution {public int[] twoSum(int[] nums, int targe…...
unity3d————[HideInInspector]
在Unity3D中,[HideInInspector]是一个属性修饰符,它的主要作用是在Unity的Inspector窗口中隐藏变量或属性。以下是关于[HideInInspector]的详细解释和作用: 作用 隐藏变量或属性:当你在脚本中使用[HideInInspector]修饰符时&…...
Soanrquber集成Gitlab 之 导入Gitlab项目
集成Gitlab 之 导入Gitlab项目 说明: Sonarquber里面的项目,顺便设置,只要在集成CI的时候,使用这个项目的项目标识即可。 当然项目名称一一对应是最好的了,所以这里讲导入Gitlab的项目,项目名称一一对应&…...
论区块链技术及应用
引言 区块链技术作为一种革命性的创新,近年来在全球范围内得到了广泛关注和应用。其去中心化、透明性和不可篡改的特性,使其在多个领域展现出了巨大的潜力。从金融到物联网,从医疗管理到政务监管,区块链正在改变我们处理信息和进…...
GPT避坑指南:如何辨别逆向、AZ、OpenAI官转
市面上有些说自己是官转,一刀只需要1块甚至几毛钱,并声称官方倍率的,很大可能就是使用的是 逆向或Azure。 如何鉴别逆向 逆向的种类很多,主要分为3类 逆向不知名A| 镜像站或偷的 key。成本约等于0,调用聊天数据可能在…...
Qt 文本文件读写与保存
Qt 文本文件读写与保存 开发工具:VS2013 QT5.8 设计UI界面,如下图所示 sample7_1QFile.h 头文件: #pragma once#include <QtWidgets/QMainWindow> #include "ui_sample7_1QFile.h"class sample7_1QFile : public QMainWin…...
Linux基础环境搭建(CentOS7)- 安装Scala和Spark
#Linux基础环境搭建(CentOS7)- 安装Scala和Spark Linux基础环境搭建(CentOS7)- 安装Scala和Spark 大家注意以下的环境搭建版本号,如果版本不匹配有可能出现问题!(spark不要下2.4版本的 会报错…...
SpringBoot 下的Excel文件损坏与内容乱码问题
序言 随着打包部署的方式的改变,原本正常运行的代码可能带来一些新的问题,比如我们现在使用SpringBoot 的方式生成Jar包直接运行,就会对我们再在Resource下的Excel文件产生影响,导入与预期不符的情况发生cuiyaonan2000163.com 比…...
官宣下代GPU存在缺陷,50系显卡或将迎来涨价
如果说 AMD 在 Ryzen 3000 系列还是和 intel 在 CPU 方面棋差一着的话,Ryzen 5000 系列就是打了个漂亮的翻身仗了。 凭借先进的 7nm 工艺制程和全新架构,让后来 intel 急忙推出「14nm」的 11 代酷睿也难以望其项背。 直到 intel 12 代发布的时候…...
使用pytorch实现LSTM预测交通流
原始数据: 免费可下载原始参考数据 预测结果图: 根据测试数据test_data的真实值real_flow,与模型根据测试数据得到的输出结果pre_flow 完整源码: #!/usr/bin/env python # _*_ coding: utf-8 _*_import pandas as pd import nu…...
C/C++(八)C++11
目录 一、C11的简介 二、万能引用与完美转发 1、万能引用:模板中的 && 引用 2、完美转发:保持万能引用左右值属性的解决方案 三、可变参数模板 1、可变参数模板的基本使用 2、push 系列和 emplace 系列的区别 四、lambda表达式…...
使用three.js 实现 自定义绘制平面的效果
使用three.js 实现 自定义绘制平面的效果 预览 import * as THREE from three import { OrbitControls } from three/examples/jsm/controls/OrbitControls.jsconst box document.getElementById(box)const scene new THREE.Scene()const camera new THREE.PerspectiveCam…...
玩转Docker | 使用Docker部署捕鱼网页小游戏
玩转Docker | 使用Docker部署捕鱼网页小游戏 一、项目介绍项目简介项目预览二、系统要求环境要求环境检查Docker版本检查检查操作系统版本三、部署捕鱼网页小游戏下载镜像创建容器检查容器状态下载项目内容查看服务监听端口安全设置四、访问捕鱼网页小游戏五、总结一、项目介绍…...
第2章 Android App开发基础
第 2 章 Android App开发基础 bilibili学习地址 github代码地址 本章介绍基于Android系统的App开发常识,包括以下几个方面:App开发与其他软件开发有什么不一 样,App工程是怎样的组织结构又是怎样配置的,App开发的前后端分离设计…...
通过 SYSENTER/SYSEXIT指令来学习系统调用
SYSENTER指令—快速系统调用 指令格式没有什么重要的内容,只有opcode ,没有后面的其他字段 指令的作用: 执行快速调用到特权级别0的系统过程或例程。SYSENTER是SYSEXIT的配套指令。该指令经过优化,能够为从运行在特权级别3的用户代码到特权级别0的操作系统或执行过程…...
Nginx开发实战——网络通信(一)
文章目录 Nginx开发框架信号处理函数的进一步完善(避免僵尸子进程)(续)ngx_signal.cxxngx_process_cycle.cxx 网络通信实战客户端和服务端1. 解析一个浏览器访问网页的过程2.客户端服务器角色规律总结 网络模型OSI 7层网络模型TCP/IP 4层模型3.TCP/IP的解释和比喻 最…...
大话软工笔记—需求分析概述
需求分析,就是要对需求调研收集到的资料信息逐个地进行拆分、研究,从大量的不确定“需求”中确定出哪些需求最终要转换为确定的“功能需求”。 需求分析的作用非常重要,后续设计的依据主要来自于需求分析的成果,包括: 项目的目的…...
MMaDA: Multimodal Large Diffusion Language Models
CODE : https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA,它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构…...
Neo4j 集群管理:原理、技术与最佳实践深度解析
Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...
令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍
文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结: 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析: 实际业务去理解体会统一注…...
【HTTP三个基础问题】
面试官您好!HTTP是超文本传输协议,是互联网上客户端和服务器之间传输超文本数据(比如文字、图片、音频、视频等)的核心协议,当前互联网应用最广泛的版本是HTTP1.1,它基于经典的C/S模型,也就是客…...
七、数据库的完整性
七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...
Scrapy-Redis分布式爬虫架构的可扩展性与容错性增强:基于微服务与容器化的解决方案
在大数据时代,海量数据的采集与处理成为企业和研究机构获取信息的关键环节。Scrapy-Redis作为一种经典的分布式爬虫架构,在处理大规模数据抓取任务时展现出强大的能力。然而,随着业务规模的不断扩大和数据抓取需求的日益复杂,传统…...
Unity中的transform.up
2025年6月8日,周日下午 在Unity中,transform.up是Transform组件的一个属性,表示游戏对象在世界空间中的“上”方向(Y轴正方向),且会随对象旋转动态变化。以下是关键点解析: 基本定义 transfor…...
何谓AI编程【02】AI编程官网以优雅草星云智控为例建设实践-完善顶部-建立各项子页-调整排版-优雅草卓伊凡
何谓AI编程【02】AI编程官网以优雅草星云智控为例建设实践-完善顶部-建立各项子页-调整排版-优雅草卓伊凡 背景 我们以建设星云智控官网来做AI编程实践,很多人以为AI已经强大到不需要程序员了,其实不是,AI更加需要程序员,普通人…...
精益数据分析(98/126):电商转化率优化与网站性能的底层逻辑
精益数据分析(98/126):电商转化率优化与网站性能的底层逻辑 在电子商务领域,转化率与网站性能是决定商业成败的核心指标。今天,我们将深入解析不同类型电商平台的转化率基准,探讨页面加载速度对用户行为的…...
