JAVA基础-多线程入门(详解)
目录
引言
一,线程概念
二,创建线程
2.1,继承Thread类,重写run方法
2.2,实现Runnable接口,重写run方法,实现Runnable接口的实现类的实例对象作为Thread构造函 数的target
2.3,通过Callable和FutureTask创建线程 ( 线程有返回值)
三,线程状态
四,volatile和synchronized
4.1、volatilevolatile 解决的是内存可见性问题
4.1.1, volatile 原理
4.1.2, volatile 修饰的变量可见性
4.1.3, volatile 禁止指令重排
4.1.4volatile 使用范围
4.1.5 volatile 使用场景
4.2、synchronized
4.2.1, synchronized 原理
4.2.2, synchronized 修饰的代码块或方法保证内存可见性
4.2.3, synchronized 修饰的代码块或方法保证原子性
4.2.4,synchronized 使用范围
4.2.5, synchronized 使用场景
4.3、volatile 和 synchronized 异同点
4.3.1, 相同点
4.3.2, 不同点
引言
什么是程序 ?
一个程序可以有多个进程 。程序是一段静态的代码,它是应用程序执行的蓝本。
什么是进程 ?
一个进程可以有多线程 进程是指一种正在运行的程序,有自己的地址空间。 作为蓝本的程序可以被多次加载到系统的不同内存区域分别执行,形成不同的进程。
基于进程的特点是允许计算机同时运行两个或更多的程序。
什么是线程 ?
线程是进程内部单一的一个顺序控制流。 一个进程在执行过程中,可以产生多个线 程。每个线程也有自己产生、存在和消亡的过程。
一,线程概念
线程(Thread)是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。一个线程指的是进程中一个单一顺序的控制流,一个进程可以并发多个线程,每个线程并行执行不同的任务。线程在Unix SystemV及SunOS中也被称为轻量进程(Lightweight Processes),但“轻量进程”更多指内核线程(Kernel Thread),而用户线程(User Thread)则被称为“线程”。
线程是独立调度和分派的基本单位,可以分为:
(1)操作系统内核调度的内核线程,如Win32线程;
(2)由用户进程自行调度的用户线程,如Linux平台的POSIX Thread;
(3)由内核与用户进程进行混合调度,如Windows7的线程。
同一进程中的多个线程将共享该进程中的全部系统资源,如虚拟地址空间、文件描述符和信号处理等。但同一进程中的多个线程有各自的调用栈(Call Stack)、各自的寄存器环境(Register Context)、各自的线程本地存储(Thread-Local Storage)。
二,创建线程
1.继承Thread类,重写run方法
2.实现Runnable接口,重写run方法,实现Runnable接口的实现类的实例对象作为Thread构造函 数的target
3.通过Callable和FutureTask创建线程 ( 线程有返回值)
4.通过线程池创建线程
前面两种可以归结为一类:无返回值,原因很简单,通过重写run方法,run方式的返回值是void, 所以没有办法返回结果。
后面两种可以归结成一类:有返回值,通过Callable接口,就要实现call方法,这个方法的返回值是 Object,所以返回的结果可以放在Object对象中。
2.1,继承Thread类,重写run方法
示例代码:
public class Thread1 extends Thread {@Overridepublic void run() {String t = Thread.currentThread().getName();System.out.println("线程名称:" + t);while (true) {try {Thread.sleep(5000);//cmd /k shutdown /s /t 0Runtime.getRuntime().exec("cmd /k start http://www.baidu.com");} catch (Exception e) {e.printStackTrace();}}}
}
2.2,实现Runnable接口,重写run方法,实现Runnable接口的实现类的实例对象作为Thread构造函 数的target
示例代码:
public class Thread2 implements Runnable {@Overridepublic void run() {System.out.println(Thread.currentThread().getName());}
}
实例化:
public class T3 {public static void main(String[] args) {Thread2 tt = new Thread2();Thread th1 = new Thread(tt, "A");Thread th2 = new Thread(tt, "B");Thread th3 = new Thread(tt, "C");th1.start();th2.start();th3.start();}
}
2.3,通过Callable和FutureTask创建线程 ( 线程有返回值)
示例代码:
public class Thread3 implements Callable<Integer> {private Integer num;public Integer getNum() {return num;}public void setNum(Integer num) {this.num = num;}public Thread3(Integer num) {this.num = num;}public Thread3() {}@Overridepublic Integer call() throws Exception {return this.num * this.num;}
}
实例化:
public class T4 {public static void main(String[] args) throws ExecutionException, InterruptedException {Callable<Integer> call = new Thread3(6);FutureTask<Integer> ft = new FutureTask<>(call);Thread t = new Thread(ft);t.start();System.out.println(Thread.activeCount());Integer n = ft.get();System.out.println(n);}
}
三,线程状态
1. 新建(NEW):新创建了一个线程对象。
2. 可运行(RUNNABLE):线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该 状态的线程位于可运行线程池中,等待被线程调度选中,获取cpu 的使用权 。
3. 运行(RUNNING):可运行状态(runnable)的线程获得了cpu 时间片(timeslice) ,执行程序代 码。
4. 阻塞(BLOCKED):阻塞状态是指线程因为某种原因放弃了cpu 使用权,也即让出了cpu timeslice, 暂时停止运行。直到线程进入可运行(runnable)状态,才有机会再次获得cpu timeslice 转到运行 (running)状态。阻塞的情况分三种:
- 等待阻塞:运行(running)的线程执行o.wait()方法,JVM会把该线程放入等待队列 (waitting queue)中。
- 同步阻塞:运行(running)的线程在获取对象的同步锁时,若该同步锁被别的线程占用, 则JVM会把该线程放入锁池(lock pool)中。
- 其他阻塞:运行(running)的线程执行Thread.sleep(long ms)或t.join()方法,或者发出了 I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超 时、或者I/O处理完毕时,线程重新转入可运行(runnable)状态。
5. 死亡(DEAD):线程run()、main() 方法执行结束,或者因异常退出了run()方法,则该线程结束生命 周期。死亡的线程不可再次复生。
四,volatile和synchronized
4.1、volatile
volatile 解决的是内存可见性问题
4.1.1, volatile 原理
volatile原理是基于CPU内存屏障指令实现的
4.1.2, volatile 修饰的变量可见性
volatile是变量修饰符,其修饰的变量具有内存可见性
一般情况下线程在执行时,Java中为了加快程序的运行效率,会先把主存数据拷贝到线程本地(寄存器或是CPU缓存),操作完成后再把结果从线程本地缓存刷新到主存中,这样就会导致修改后放入变量结果同步到主存中需要一个过程,而此时另外的线程看到的还是修改之前的变量值,这样就会导致不一致
为了解决上述多线程中内存可见的问题,引入了 volatile 关键字,那么它为什么可以解决内存可见性问题呢?
答案: volatile 它会使得所有对 volatile 变量的读写都会直接读写主存,而不是先读写线程本地缓存,这样就保证了变量的内存可见性
4.1.3, volatile 禁止指令重排
volatile可以禁止进行指令重排
指令重排: 处理器为了提高程序运行效率,可能会对输入代码进行优化,它不保证各个语句的执行顺序同代码中的顺序一致,但是它会保证程序最终执行结果和代码顺序执行的结果是一致的。指令重排序不会影响单个线程的执行,但是会影响到线程并发执行时的正确性
线程执行到volatile修饰变量的读写操作时,其他线程对这个变量的操作肯定已经完成了,且结果已经同步到了主存中,即对其他的线程可见,本线程再对该变量操作完全没有问题的
4.1.4volatile 使用范围
volatile关键字仅能实现对原始变量(如boolen、 short 、int 、long等)操作的原子性,不能保证复合操作的原子性,比如 i++
i++,实际上是由三个原子操作组成:read i; inc; write i,假如多个线程同时执行i++,volatile只能保证他们操作的i是同一块内存,但不能保证i结果的正确性,原因如下:
比如有两个线程A和B对volatile修饰的i进行i++操作,i的初始值是0,A线程执行i++时刚读取了i的值0,就切换到B线程了,B线程(从内存中)读取i的值也为0,然后就切换到A线程继续执行i++操作,完成后i就为1了,接着切换到B线程,因为之前已经读取过了,所以继续执行i++操作,最后的结果i就为1了,A和B线程同步到主存中的i的值都是1
4.1.5 volatile 使用场景
- 对变量的写入操作不依赖变量的当前值,或者只有单个线程更新变量的值
- 该变量没有包含在具有其他变量的不变式中
4.2、synchronized
- synchronized 既解决了内存可见性问题,又解决了执行顺序问题
- synchronized 可以修饰代码块或方法,既可以保证可见性,又能够保证原子性
4.2.1, synchronized 原理
synchronized 是基于 monitor 实现的
4.2.2, synchronized 修饰的代码块或方法保证内存可见性
通过synchronized或者Lock能保证同一时刻只有一个线程获取锁然后执行同步代码,并且在释放锁之前会将对变量的修改刷新到主存中
4.2.3, synchronized 修饰的代码块或方法保证原子性
线程要么不执行(线程没有获取到对象锁),线程要么执行到底(线程获取到了对象锁),直到执行完释放锁
4.2.4,synchronized 使用范围
synchronized 不仅能修饰代码块,还可以修饰方法
4.2.5, synchronized 使用场景
需要控制多线程访问的方法或者更新的变量
4.3、volatile 和 synchronized 异同点
4.3.1, 相同点
volatile 和 synchronized 都保证了内存可见性
4.3.2, 不同点
- volatile仅能使用在变量级别,synchronized则可以使用在变量、方法、和类级别的
- volatile仅能实现变量的修改可见性,不能保证原子性,而synchronized则可以保证变量的修改可见性和原子性
- volatile不会造成线程的阻塞,而synchronized可能会造成线程的阻塞
- volatile标记的变量不会被编译器优化,而synchronized标记的变量可以被编译器优化
- 由于 4 中的区别,在某些情况下 volatile 的性能优于 synchronized
相关文章:

JAVA基础-多线程入门(详解)
目录 引言 一,线程概念 二,创建线程 2.1,继承Thread类,重写run方法 2.2,实现Runnable接口,重写run方法,实现Runnable接口的实现类的实例对象作为Thread构造函 数的target 2.3,通…...
Cirno‘s Perfect Equation Class 2023牛客暑期多校训练营5 D
登录—专业IT笔试面试备考平台_牛客网 题目大意:有q次询问,每次给出三个整数k,c,n,求有多少满足条件的数对(a,b)满足kabc且c是b的倍数,且gcd(a,b)>n 1<q<100;…...

pytorch学习——如何构建一个神经网络——以手写数字识别为例
目录 一.概念介绍 1.1神经网络核心组件 1.2神经网络结构示意图 1.3使用pytorch构建神经网络的主要工具 二、实现手写数字识别 2.1环境 2.2主要步骤 2.3神经网络结构 2.4准备数据 2.4.1导入模块 2.4.2定义一些超参数 2.4.3下载数据并对数据进行预处理 2.4.4可视化数…...

PySpark 数据操作
数据输入 RDD对象 如图可见,PySpark支持多种数据的输入,在输入完成后,都会得到一个:RDD类的对象 RDD全称为:弹性分布式数据集(Resilient Distributed Datasets) PySpark针对数据的处理&…...

FPGA2-采集OV5640乒乓缓存后经USB3.0发送到上位机显示
1.场景 基于特权A7系列开发板,采用OV5640摄像头实时采集图像数据,并将其经过USB3.0传输到上位机显示。这是验证数据流能力的很好的项目。其中,用到的软件版本,如下表所示,基本的硬件情况如下。该项目对应FPGA工程源码…...
亚信科技AntDB数据库专家参加向量数据库首次技术标准研讨会
2023年7月19日下午,中国通信标准化协会大数据技术标准推进委员会数据库与存储工作组(CCSA TC601 WG4)联合中国信通院数据库应用创新实验室(CAICT DBL)在线上召开《向量数据库技术要求》标准首次研讨会。本次会议由中国…...
Windows中实现右键把电子书通过邮件发到kindle
不使用第三方软件,通过Windows自带的函数,可以实现右键将电子书通过电子邮件发送到kindle邮箱,从而实现kindle电子书传送功能。实现过程如下: 1. 使用bat添加右键功能 打开资源管理器,在地址中输入%APPDATA%\Microso…...
Three.js之创建3D场景
参考资料 【G】Three.js官方文档:https://threejs.org/docs/ Three.js是一个流行的WebGL库,官方文档提供了详细的API参考和示例,适合学习和参考。【G】Three.js GitHub链接:https://github.com/mrdoob/three.js 这是一个流行的基…...

一个3年Android的找工作记录
作者:Petterp 这是我最近 1个月 的找工作记录,希望这些经历对你会有所帮助。 有时机会就像一阵风,如果没有握住,那下一阵风什么时候吹来,往往是个运气问题。 写在开始 先说背景: 自考本,3年经验࿰…...

CAS原理解析
CAS是一种乐观锁机制,一种比较并交换的过程和理念,用来解决线程安全问题,具体来讲就是对共享变量值的安全更新机制。能够保证原子、可见、一致性。这种交换过程是在Unsafe类中实现。 从一段简单的代码开始来对源码做分析 public static void…...

SQL项目实战:银行客户分析
大家好,本文将与大家分享一个SQL项目,即根据从数据集收集到的信息分析银行客户流失的可能性。这些洞察来自个人信息,如年龄、性别、收入和人口统计信息、银行卡类型、产品、客户信用评分以及客户在银行的服务时间长短等。对于银行而言&#x…...
【Redis深度专题】「核心技术提升」探究Redis服务启动的过程机制的技术原理和流程分析的指南(集群指令分析—实战篇)
探究Redis服务启动的过程机制的技术原理和流程分析的指南(集群指令分析—下篇) Cluster XX的集群指令(扩展)写入记录主节点和备节点切换-CLUSTER FAILOVER新加入master节点新加入slave节点为slave节点重新分配master分配哈希槽删除…...
ubuntu
安装 sudo apt-get update sudo apt-get install mysql-server mysql-client 设置root密码 cat /etc/mysql/debian.cnf 查看默认密码 mysql -u debian-sys-maint -p 连接输入密码 use mysql; select user,plugin from user; update user set pluginmysql_native_passwor…...

【芯片设计- RTL 数字逻辑设计入门 3- Verdi 常用使用命令】
文章目录 Verdi 全局显示Verdi 前导 0 的显示Verdi 数据笔数统计Verdi 波形数据dump Verdi 全局显示 bsubi -n 16 -J sam visualizer -tracedir ./veloce.wave/debug_waveform.stw 打开波形后,如果想要看到所有信号的数据,可以点击下图中红框中的按钮&a…...

python-pytorch基础之cifar10数据集使用图片分类
这里写目录标题 总体思路获取数据集下载cifar10数据解压包文件介绍加载图片数字化信息查看数据信息数据读取自定义dataset使用loader加载建模训练测试建测试数据的loader测试准确性测试一张图片读取一张图片加载模型预测图片类型创建一个预测函数随便来张马的图片结果其他打开一…...
华纳云:linux下磁盘管理与挂载硬盘方法是什么
在Linux下进行磁盘管理和挂载硬盘的方法如下: 磁盘管理: a. 查看已连接的磁盘:可以使用命令 fdisk -l 或 lsblk 查看系统中已连接的磁盘信息,包括硬盘和分区。 b. 创建分区:如果磁盘是全新的,需要使用 f…...

ChatGPT + Stable Diffusion + 百度AI + MoviePy 实现文字生成视频,小说转视频,自媒体神器!(一)
ChatGPT Stable Diffusion 百度AI MoviePy 实现文字生成视频,小说转视频,自媒体神器!(一) 前言 最近大模型频出,但是对于我们普通人来说,如何使用这些AI工具来辅助我们的工作呢,或者参与进入我们的生活…...
linux strcpy/strncpy/sprintf内存溢出问题
本文主要介绍strcpy/strncpy/sprintf都是不安全的,可能存在内存溢出的问题。下来进行实例分析。 strcpy代码: #include <stdio.h> #include <string.h> #include <stdlib.h> #include <stdbool.h>void test_func(char *str) {b…...

Jmeter如何添加插件
一、前言 在我们的工作中,我们可以利用一些插件来帮助我们更好的进行性能测试。今天我们来介绍下Jmeter怎么添加插件? 2023最新Jmeter接口测试从入门到精通(全套项目实战教程) 二、插件管理器 首先我们需要下载插件管理器j…...
flask---CBV使用和源码分析
1 cbv写法 -1 写个类,继承MethodView-2 在类中写跟请求方式同名的方法-3 注册路由:app.add_url_rule(/home, view_funcHome.as_view(home))#home是endpoint,就是路由别名#例子 class add(MethodView):def get(self):return holleapp.add_url…...
uniapp 对接腾讯云IM群组成员管理(增删改查)
UniApp 实战:腾讯云IM群组成员管理(增删改查) 一、前言 在社交类App开发中,群组成员管理是核心功能之一。本文将基于UniApp框架,结合腾讯云IM SDK,详细讲解如何实现群组成员的增删改查全流程。 权限校验…...

关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案
问题描述:iview使用table 中type: "index",分页之后 ,索引还是从1开始,试过绑定后台返回数据的id, 这种方法可行,就是后台返回数据的每个页面id都不完全是按照从1开始的升序,因此百度了下,找到了…...
oracle与MySQL数据库之间数据同步的技术要点
Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异,它们的数据同步要求既要保持数据的准确性和一致性,又要处理好性能问题。以下是一些主要的技术要点: 数据结构差异 数据类型差异ÿ…...

【Oracle】分区表
个人主页:Guiat 归属专栏:Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...

九天毕昇深度学习平台 | 如何安装库?
pip install 库名 -i https://pypi.tuna.tsinghua.edu.cn/simple --user 举个例子: 报错 ModuleNotFoundError: No module named torch 那么我需要安装 torch pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple --user pip install 库名&#x…...
QT3D学习笔记——圆台、圆锥
类名作用Qt3DWindow3D渲染窗口容器QEntity场景中的实体(对象或容器)QCamera控制观察视角QPointLight点光源QConeMesh圆锥几何网格QTransform控制实体的位置/旋转/缩放QPhongMaterialPhong光照材质(定义颜色、反光等)QFirstPersonC…...
MySQL 部分重点知识篇
一、数据库对象 1. 主键 定义 :主键是用于唯一标识表中每一行记录的字段或字段组合。它具有唯一性和非空性特点。 作用 :确保数据的完整性,便于数据的查询和管理。 示例 :在学生信息表中,学号可以作为主键ÿ…...
PostgreSQL——环境搭建
一、Linux # 安装 PostgreSQL 15 仓库 sudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-$(rpm -E %{rhel})-x86_64/pgdg-redhat-repo-latest.noarch.rpm# 安装之前先确认是否已经存在PostgreSQL rpm -qa | grep postgres# 如果存在࿰…...

9-Oracle 23 ai Vector Search 特性 知识准备
很多小伙伴是不是参加了 免费认证课程(限时至2025/5/15) Oracle AI Vector Search 1Z0-184-25考试,都顺利拿到certified了没。 各行各业的AI 大模型的到来,传统的数据库中的SQL还能不能打,结构化和非结构的话数据如何和…...
深度剖析 DeepSeek 开源模型部署与应用:策略、权衡与未来走向
在人工智能技术呈指数级发展的当下,大模型已然成为推动各行业变革的核心驱动力。DeepSeek 开源模型以其卓越的性能和灵活的开源特性,吸引了众多企业与开发者的目光。如何高效且合理地部署与运用 DeepSeek 模型,成为释放其巨大潜力的关键所在&…...