Java并发编程 - 基础

Java并发编程基础小结 并发编程的核心问题与解决方案 本文从多线程的必要性、优势入手,深入分析了并发编程需要关注的三大核心问题:安全性问题(如数据竞争)、活跃性问题(如死锁、活锁)以及性能问题(如线程切换开销)。作者通过生动的代码示例和图示,展示了在多线程环境下可能出现的典型问题,并指出JVM中线程与进程的资源分配差异。文章还解释了程序计数器、虚拟机栈等线程私有区域的设计原理,以及如何利用"栈封闭"技术解决线程安全问题。全文为Java开发者提供了对并发编程本质问题的系统性思考框架。 阅读详情

并发的历史

操作系统的发展使得多个程序能够同时运行, 由操作系统来分配资源, 如果需要的话, 进程会通过一些原始的机制相互通信, 主要分为消息传递和共享内存两种:

  • 消息传递: Socket, 信号处理(signal handlers), 信号量(semaphores)和文件等.

  • 共享内存

    线程共享其所属进程的内存地址空间, 因此所有同一进程中的线程访问相同的变量, 并从同一个堆中分配对象, 这相对于进程间通信(inter-process)机制来说实现了良好的数据共享. 但是如果没有明确的同步来管理共享数据, 一个线程可能会修改其他线程正在使用的数据, 产生意外的结果.


线程简介

线程优先级

Java线程中, 通过一个int变量priority来控制优先级, 范围为1~10, 通过setPriority(int)方法来修改优先级, 默认优先级是5, 操作系统通常会忽略自己手动设定的线程优先级(比如Mac OS X, Ubuntu等), 作为程序开发者一般也不需要手动调整

线程的状态

一共有6种可能的状态:

状态名称说明
NEW初始状态, 仅被构建, 没有启用start()方法
RUNNABLE可运行状态, 将操作系统中定义的’就绪’和’运行’统称为’RUNNABLE’
BLOCKED阻塞状态, 需要获取锁
WAITING等待状态, 需要其他线程发出通知或者中断, 然后重新竞争锁
TIMED_WAITING定时等待状态, 和WAITING类似, 不过不会无限等待,具有一个超时自动返回的功能, 不会引起锁持有状况的变化
TERMINATED终止状态, 线程已执行完毕

可以使用jstack工具来进行查看运行时线程的信息, 步骤如下:

  1. 使用jps命令查看Java进程;
  2. 找出当前运行程序的进程号, 这里以2100为例, 运行jstack 2100即可.

Java线程状态变迁示意图:

Java线程状态变迁示意图

Daemon线程

Daemon线程是一种后台支持型线程, 因为它主要被用作程序中后台调度以及支持性工作.
当一个JVM中不存在非Daemon线程的时候, JVM将会立即退出(所以不能在finally块中执行关闭或者清理资源的逻辑)

线程间通信

volatile和synchronized关键字

实际上是通过共享内存实现的线程间通信.

通知/等待机制

是任何Java对象都具备的, 这些方法定义在java.lang.Object上:

方法名称描述
notify()通知一个在对象上等待的线程, 使其从wait()方法返回, 而返回的前提是该线程获取到了对象的锁
notifyAll()通知所有等待在该对象上的线程
wait()调用该方法的线程进入WAITING状态, 同时释放对象锁, 只有等待另外线程的通知或被中断才会返回
wait(long)定时等待, 单位毫秒, 超时返回
wait(long, int)更细粒度的定时, 可以达到纳秒级别

等待/通知的经典范式

就是消费者/生产者模型

Thread.join()的使用

实际上是通知/等待机制的一种实现.

ThreadLocal的使用

是线程变量, 以ThreadLocal对象为键, 任意对象为值的存储结构. 这个结构是与线程对象绑定的, 也就是说即使是使用线程不安全的数据结构, 如此包装后也可以安全使用.


并发编程中的挑战

并发编程中有许多单线程程序中没有的挑战.

上下文切换

即使是单核CPU也支持多线程执行代码, CPU会通过给每个线程分配CPU时间片来实现这个机制. 时间片一般是几十毫秒. 当前任务执行一个时间片后会切换到下一个任务, 但是在切换前会保存上一个任务的状态, 以便下次切换回这个任务时, 可以再加载这个任务的状态. 所以任务从保存到再加载的过程就是一次上下文切换. 上下文切换会影响多线程的执行速度.

并发执行的速度不一定比串行快, 因为线程有创建和上下文切换的开销. 当并发运算次数较少的时候, 上下文切换的开销会显著影响累积计算时间.

如何较少上下文切换

  1. 无锁并发编程

    多线程竞争锁时, 会引起上下文切换, 避免使用锁的方法举例: 通过将数据的ID按照Hash算法取模分段, 不同的线程处理不同段的数据.

  2. CAS算法

    Java的Atomic包使用的就是CAS算法来更新数据, 不需要加锁, 举例: AutomicLong类型

  3. 使用最少线程

    避免大量线程处于等待状态

  4. 协程

    在单线程里实现多任务的调度, 在单线程里维持多个任务间的切换.

死锁

避免死锁的几个方法

  • 避免一个线程同时获取多个锁;
  • 尝试使用定时锁, 使用lock.tryLock(timeout)来替代使用内部锁机制;

如何保证线程安全

使用无状态对象

无状态对象永远是线程安全的

这里以一个Servlet为例, 说明什么叫做无状态:

因为Servlet对象不包含属性, 也没有引用其他类的属性, 只有本地变量. 本地变量唯一的存储在本线程的栈中, 只有执行线程(本Servlet)才能访问, 所以是线程安全的.

使用原子操作

  • 读-改-写 不是原子的, 例如count++
  • check-then-run, 不是原子的, 例如: if (i != null) i = new SomeClass();

无状态+单个内置原子变量=线程安全, 但是两个及以上的原子变量!=线程安全

为了维持状态一致性, 必须将相关的状态变量在同一个原子操作内更新

注意

并不是说将一个类的所有方法都标注成synchronized, 然后这个类就是线程安全的了, 举个例子, 如果两个属性之间需要同步更新, 然后分别提供了setter方法, 那么在类外使用的时候, 就有可能引发安全问题.

如何在Java中实现高效的并发编程:从基础到进阶 在Java中实现高效的并发编程涉及多个层面的知识,从基础的线程管理到高级的并发控制工具,如。 阅读详情

相关推荐

疯狂 Java 讲义——从基础知识到并发编程

作者:禅与计算机程序设计艺术 1.简介 Java 是一种在全球范围内广泛使用的、面向对象编程语言。虽然 Java 在设计之初就提供了一些安全性和并发性支持,但是随着 Java 的流行,它逐渐变成了一个“现代化”的编程语言。本讲义将带领读者了解 Java 各种语言特性和语法规则,以及其中的应用场景。通过阅

AI天才研究院 2429

【高并发专题】-java线程安全-原子性-Automic包详解

线程安全性 当多个线程同时访问某个类时,不管采取何种线程调度方法,在主调代码中不需要采取额外的同步或者协同,这个类都能表现出正确的行为,那么这个类就是线程安全的. 线程安全的三个特性 原子性:提供了互斥访问,同一时刻只能有一个线程来对它进行操作. 可见性:一个线程对主内存的修改会被其他线程所看到. 有序性:编译器和处理器可能会为了性能对操作指令进行重新排序,重新排序后对单个线程的程序执行...

老汉健身的博客 2099

电子技术设计——16×16点阵汉字显示设计

同时,设计还应注重提升显示品质,以保证汉字的稳定展示和观感舒适。本设计的目的是构建一个能够准确在LED点阵上展示汉字的系统,并允许用户通过输入设备来选择所需的汉字,我们将验证设计方案的实际操作性和效果,以确保其满足设计目标。在LED点阵显示和汉字信息处理技术的结合下,研究者们着手研究如何在LED点阵上有效地显示汉字,并提出了一系列显示算法和优化策略,旨在实现清晰且易于阅读的汉字显示效果。首先,你需要准备16×16的LED点阵面板,通常这些点阵是8×8点阵的两倍,因此可以由两个8×8的点阵组合而成。

weixin_68094467的博客 1532

LongAdder理解

LongAdder是对Long类型字段进行多线程累加的工具类,在线程竞争较多后,LongAdder比AutomicLong更有效率; AutomicLong 当调用自增方法时,是使用cas + 自旋的方式 实现的;相对慢的原因是,仅对 valueoddSet 进行操作; public final long incrementAndGet() { return unsafe.getAndAddLong(this, valueOffset, 1L) + 1L; } public

weixin_38038479的博客 556

openeuler在线/离线安装docker服务

openeuler在线/离线安装docker服务

haixuti7的博客 1070

【python】import pandas as pd用法

是 Python 里最常用的数据分析库之一。 的意思是:导入 pandas 库,并给它起个别名 。这样用起来更简洁: 下面总结 pandas 的常见用法(配例子)。目录🔹 1. 数据结构(1) Series(一维数据,类似于数组 + 标签)(2) DataFrame(二维数据表,类似于 Excel 表格)🔹 2. 数据读写🔹 3. 数据查看🔹 4. 数据选择与索引🔹 5. 数据清洗🔹 6. 数据运算🔹 7. 数据筛选(布尔索引)🔹 8. 分组与聚合🔹 9. 排序 Pandas 常用方

2401_86285609的博客 1529

高并发编程之AtomicLong讲解

一、AtomicLong介绍 AtomicLong是作用是对长整形进行原子操作。 在32位操作系统中,64位的long 和 double 变量由于会被JVM当作两个分离的32位来进行操作,所以不具有原子性。而使用AtomicLong能让long的操作保持原子型。 二、AtomicLong的几个常用方法 ①.创建具有初始值 0 的新 AtomicLong。 package chapter3.Atom...

weixin_42146366的博客 3万+

Matlab结果性能评价---rms函数(计算矩阵、数组和向量元素均方根)

实例1:创建一个向量(正弦波)并计算其均方根值 实例2:创建一个二维矩阵并计算其均方根值 实例3:计算二维矩阵沿指定维度的均方根值 本例程配套完整源码下载 均方根(Root-Mean-Square Level): 向量x的均方根值为沿着指定的维度执行求和: 语法描述: y = rms(x)返回输入x的均方根值。如果x是行或列向量,y是实数值标量。对于大小尺寸大于1矩阵x,y包含沿x的第一个数组维度计算的均方根值。例如,如果x是N > 1的N*M矩阵,那么y是1*M行向量,对应x矩..

qq_32809093的博客 3万+

Java中的13个原子操作类

Java中的13个原子操作类(明明有12个,我不知道为啥说13个)1、原子更新基本类型类2、原子更新数组3、原子更新引用类型4、原子更新字段类   JDK1.5开始提供了java.util.concurrent.atomic包(简称Automic包),这个包中的原子操作类提供了一种用法简单、性能高效、线程安全地更新一个变量的方式。   变量的类型有很多种,所以在Automic包一共提供了13个类,属于4种类型的原子更新方式,分别是原子更新基本类型、原子更新数组、原子更新引用和原子更新属性(字段)。Atomi

waiting971118的博客 1707

技术面 - 手撕算法题整理

这篇博客整理了华为OD面试中涉及的算法题,包括LeetCode热门题目、OD原题和需要手写的算法,如二分查找、冒泡排序等。建议优先刷"hot100"的LeetCode题目,全刷OD原题,以及掌握手撕算法的基本原理。

m0_73659489的博客 1023

【STK】手把手教你利用STK进行覆盖分析05-方位覆盖分析、覆盖网络检查工具和单对象覆盖分析

这一篇是我们STK覆盖模块的理论部分的最后一篇文章,之后会找尽可能多的论文来复现论文中关于STK覆盖模块的仿真的部分,到时候大家遇到不会的就可以结合前面的理论部分来看。

weixin_44184852的博客 1493

LongAdder源码分析

只需要实现session监听器,然后再根据具体逻辑进行操作://统计当前在线用户个数 public class UserCountListener implements HttpSessionListener { public void sessionCreated(HttpSessionEvent se) { ServletContext context = se.getSess

u012572955的专栏 3067

R语言 百度坐标转换至WGS84坐标

本文利用R语言封装了百度坐标转换至WGS84坐标的函数,亲测有效,提供了便捷的百度坐标转换方法。

qingchen98的博客 2135

《Java并发编程的艺术》之 Java并发编程基础

《Java并发编程的艺术》之 Java并发编程基础 文章目录《Java并发编程的艺术》之 Java并发编程基础线程简介什么是线程代码清单4-1 MultiThread.java解析为什么要使用多线程更多的处理器核心更快的响应时间线程优先级代码清单4-2 Priority.java结果注意参数解析线程的状态注意Daemon线程注意注意启动和终止线程构造线程代码清单4-6 Thread.java启动线程注意理解中断代码清单4-7 Interrupted.java过期的suspend()、resume()和sto

weixin_44019182的博客 2496

Python 爬虫实战:就业市场趋势数据抓取与行业洞察

在当今竞争激烈的就业市场中,了解行业趋势和就业形势对于求职者、学生以及人力资源专业人士来说至关重要。通过获取和分析就业市场数据,我们可以深入了解不同行业的招聘需求、薪资水平、技能要求等关键信息,从而为职业规划和人才发展提供有力支持。

yansideyucsdn的博客 1406

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

Java 并发编程基础

Java 并发编程基础,涉及并发与并行的区别、进程与线程的区别、Java 线程基础、共享资源访问控制等内容。

leileiluoluo的博客 2177

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

深入浅出Java并发编程:线程基础

通过本文的学习,我们详细探讨了Java并发编程中的线程基础,包括进程与线程的区别、线程的创建方式线程的生命周期守护线程与用户线程、以及线程优先级与调度策略。掌握这些基础知识是进一步学习并发编程的关键。在实际开发中,理解并正确使用这些概念可以帮助我们构建高效、稳定的多线程应用。然而,并发编程的复杂性远不止于此,后续我们还将深入探讨线程安全、锁机制、线程通信等高级主题。

在技术的广袤天地里,本博客如精准罗盘。剖析前沿科技,深掘代码奥秘,以精炼笔触,带您穿越复杂技术迷宫,速达知识彼岸。 1934

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

java并发编程基础

java并发编程基础

靠脑袋是真滴记不住啊!!!!!!!! 297

【Java并发编程系列】- Java并发编程基础

默认情况下Java进程需要等其中所有线程全结束才会结束,但若设置某线程为守护线程,则在其他线程全结束的情况下,即使守护线程还没执行完,Java进程也会停止,守护线程自动被结束。多线程时,每个线程都会维护自己的栈和栈帧,每个线程只能有一个活动栈帧,对应当前正在执行的方法,方法执行完会返回到栈帧中方法出口地址的位置,然后从栈中pop出栈。直接使用 run 的方式,在mian中直接调用t1线程的run方法,则会是main方法调用执行run方法中的内容,t1会一直处于在新建状态。

m0_68383079的博客 788

Java并发编程基础

进程是操作系统进行资源分配和调度的基本单位,是程序的一次执行实例。这里主要理解为对内存进行分配的基本单位,主要为内存,其余少量网络IO等。

HelloMyAndYourWorld的博客 767

Java并发编程系列之一并发理论基础

Java并发编程系列之一并发理论基础 本系列文章开始Java并发编程的进阶篇的学习,为了初学者对多线程的初步使用有基本概念和掌握,前置知识会对一些基础篇的内容进行介绍,以使初学者能够丝滑入戏。 多线程学习,真正的难点不在于多线程程序的逻辑有多复杂,而在于理清J.U.C包中各个多线程工具类之间的关系、特点及其使用场景,学习应该是从整体到局部、高屋建瓴,这对学习任何知识都至关重要。 站在上帝视角,以全局视野,抽丝剥茧,深入每个并发编程的各个包及APi的底层实现。 概览 下图为并发编程包含的所有知识。读者大致浏览

程序员田同学的博客 587

Java并发编程基础(一篇入门)

1 并发编程简介 1.1 什么是并发编程 所谓并发编程是指在一台处理器上 “同时” 处理多个任务。并发是在同一实体上的多个事件。多个事件在同一时间间隔发生。 并发编程,从程序设计的角度来说,是希望通过某些机制让计算机可以在一个时间段内,执行多个任务。从计算机 CPU 硬件层面来说,是一个或多个物理 CPU 在多个程序之间多路复用,提高对计算机资源的利用率。从调度算法角度来说,当任务数量多于 CPU 的核数时,并发编程能够通过操作系统的任务调度算法,实现多个任务一起执行。 1.2 并发编程的重要性 对于一个

行者无疆的博客 5854

《Java并发编程的艺术》第四章 Java并发编程基础

-

给时光以生命 482

Java并发编程的艺术-并发编程基础

Java从诞生开始就明智地选择了内置对多线程的支持,这使得Java语言相比同一时期的其他语言具有明显的优势。线程作为操作系统调度的最小单元,多个线程能够同时执行,这将显著提升程序性能,在多核环境中表现得更加明显。但是,过多地创建线程和对线程的不当管理也容易造成问题。本章将着重介绍Java并发编程的基础知识,从启动一个线程到线程间不同的通信方式,最后通过简单的线程池示例以及应用(简单的...

3013
上一篇: Java并发编程 - 锁 - 原理详解
下一篇: java Future用法和意义 - 一句话击破
congyh
博客等级 码龄15年 43粉丝 38原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值