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的解释和比喻 最…...
超短脉冲激光自聚焦效应
前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应,这是一种非线性光学现象,主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场,对材料产生非线性响应,可能…...
CTF show Web 红包题第六弹
提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框,很难让人不联想到SQL注入,但提示都说了不是SQL注入,所以就不往这方面想了 先查看一下网页源码,发现一段JavaScript代码,有一个关键类ctfs…...
树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频
使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...
解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八
现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet,点击确认后如下提示 最终上报fail 解决方法 内核升级导致,需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...
【配置 YOLOX 用于按目录分类的图片数据集】
现在的图标点选越来越多,如何一步解决,采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集(每个目录代表一个类别,目录下是该类别的所有图片),你需要进行以下配置步骤&#x…...
WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成
厌倦手动写WordPress文章?AI自动生成,效率提升10倍! 支持多语言、自动配图、定时发布,让内容创作更轻松! AI内容生成 → 不想每天写文章?AI一键生成高质量内容!多语言支持 → 跨境电商必备&am…...
Python如何给视频添加音频和字幕
在Python中,给视频添加音频和字幕可以使用电影文件处理库MoviePy和字幕处理库Subtitles。下面将详细介绍如何使用这些库来实现视频的音频和字幕添加,包括必要的代码示例和详细解释。 环境准备 在开始之前,需要安装以下Python库:…...
让AI看见世界:MCP协议与服务器的工作原理
让AI看见世界:MCP协议与服务器的工作原理 MCP(Model Context Protocol)是一种创新的通信协议,旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天,MCP正成为连接AI与现实世界的重要桥梁。…...
c#开发AI模型对话
AI模型 前面已经介绍了一般AI模型本地部署,直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型,但是目前国内可能使用不多,至少实践例子很少看见。开发训练模型就不介绍了&am…...
vue3+vite项目中使用.env文件环境变量方法
vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量,这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...
