java多线程编程(二)

Java多线程编程实战指南学习(二) 多线程编程的目标与挑战1.串行、并发与并行2.竞态2.1 二维表分析法:解释竞态的结果2.2 竞态的模式与产生的条件3.线程安全性4.原子性5.可见性线程的启动、停止与可见性 1.串行、并发与并行 假设有三件事A、B、C需要完成,其中完成事情A需实际投入5分钟并等待10分钟,完成事情B需要实际投入2分钟并等待8分钟,完成事情C需实际投入10分钟但不需要等待。那有以下三种方式来完成这几件事: 串行:先做事情A,待其完成再做事情B,以此类推。这种方式共需投入1个人,35分钟。 并发:这种方式也可以只投入一个人, 阅读详情

java多线程编程(二)

     volatile、synchronized及锁对比

volatile的使用优化

1、追加字节能优化性能

如果队列的头节点和尾节点都不足64字节的话,处理器会将他们都读到同一个高速缓存行中,在多处理器
下每个处理器都会缓存同样的头、尾节点,当一个处理器试图修改头节点时,会将整个缓存行锁定,会导致其他
处理器不能访问自己高速缓存中的尾节点。
通过填充字节来填满高速缓存行,避免头节点和尾节点加载到同一个缓存行,使其在修改时不会互相锁定。

什么情况下避免使用这种方法:
缓存行非64字节宽的处理器
共享变量不会频繁地写
!在java7下可能不会生效

二、synchronized 实现原理与应用:

又称为重量级锁:

java中的每一个对象都可以作为锁:

1、对于普通的同步方法,锁是当前实例对象

2、对于静态的同步方法,锁是当前类的Class对象

3、对于同步方法块,锁是Synchonized括号里配置的对象

从JVM规范中可以看到Synchonized在JVM里的实现原理,JVM基于进入和退出Moniter对象来实现方法同步和代码块同步

但两者的实现细节不一样。

代码块同步是使用monitorenter 和 monitorexit指令实现的;

而方法同步是使用的另外一种方式实现的
monitorenter指令是在编译后插入到同步代码块的开始位置,而monitorexit是插入到方法结束处和异常处,JVm
要保证每个monitorenter必须与对应的monitorexit配对,当一个monitor被持有后,它将处于锁定状态。线程执行到
moniterenter指令时,将会尝试获取对象所对应的monitor所有权,即尝试获取对象的锁。

2.2.1 Java对象头

synchronized用的锁存储在对象头中,数组对象用三个字节宽存储对象头,如果对象是非数组类型,则用2个字节宽存储对象
1个字节宽等于4字节即32bit

java对象头的长度:

32/64bit Mark Word 存储对象的hashCode或锁信息

32/64bit Class Metadata Address 存储对象类型数据的指针

32/64bit Array length 数组的长度(如果当前对象是数组)

Java对象头里的Mark Word里默认·存储对象的HashCode、分代年龄和锁位标记。32位JVM的Mark Word的默认存储结构如下:

锁状态:无锁状态 25bit:对象的hashCode 4bit:对象分代年龄 1bit是否是偏向锁:0 2bit:锁标志位

Mark Word的状态变化:
在这里插入图片描述

64位虚拟机下,Mark Word是64bit大小的,其存储结构如下:

在这里插入图片描述

2.2.2锁的升级与对比:

Java SE 1.6为了减少获得锁和释放锁带来的性能消耗,引入了“偏向锁”和“轻量级锁”,在
Java SE 1.6中,锁一共有4种状态,级别从低到高依次是:无锁状态、偏向锁状态、轻量级锁状
态和重量级锁状态,这几个状态会随着竞争情况逐渐升级。锁可以升级但不能降级,意味着偏
向锁升级成轻量级锁后不能降级成偏向锁。这种锁升级却不能降级的策略,目的是为了提高
获得锁和释放锁的效率,

HotSpot作者认为大多数情况下,锁不仅不存在多线程竞争,而且总是由同
一线程多次获得,为了让线程获得锁的代价更低而引入了偏向锁。

当一个线程访问同步块并
获取锁时,会在对象头和栈帧中的锁记录里存储锁偏向的线程ID,以后该线程在进入和退出
同步块时不需要进行CAS操作来加锁和解锁,只需简单地测试一下对象头的Mark Word里是否
存储着指向当前线程的偏向锁。

如果测试成功,表示线程已经获得了锁。如果测试失败,则需
要再测试一下Mark Word中偏向锁的标识是否设置成1(表示当前是偏向锁):如果没有设置,则
使用CAS竞争锁;如果设置了,则尝试使用CAS将对象头的偏向锁指向当前线程。

(1)偏向锁的撤销

偏向锁使用了一种等到竞争出现才释放锁的机制,所以当其他线程尝试竞争偏向锁时,
持有偏向锁的线程才会释放锁。偏向锁的撤销,需要等待全局安全点(在这个时间点上没有正
在执行的字节码)。它会首先暂停拥有偏向锁的线程,然后检查持有偏向锁的线程是否活着,
如果线程不处于活动状态,则将对象头设置成无锁状态;如果线程仍然活着,拥有偏向锁的栈
会被执行,遍历偏向对象的锁记录,栈中的锁记录和对象头的Mark Word要么重新偏向于其他
线程,要么恢复到无锁或者标记对象不适合作为偏向锁,最后唤醒暂停的线程。图2-1中的线
程1演示了偏向锁初始化的流程,线程2演示了偏向锁撤销的流程。
在这里插入图片描述

(2)关闭偏向锁

偏向锁在Java 6和Java 7里是默认启用的,但是它在应用程序启动几秒钟之后才激活,如
有必要可以使用JVM参数来关闭延迟:-XX:BiasedLockingStartupDelay=0。如果你确定应用程
序里所有的锁通常情况下处于竞争状态,可以通过JVM参数关闭偏向锁:-XX:-
UseBiasedLocking=false,那么程序默认会进入轻量级锁状态。

2.轻量级锁

(1)轻量级锁加锁

线程在执行同步块之前,JVM会先在当前线程的栈桢中创建用于存储锁记录的空间,并
将对象头中的Mark Word复制到锁记录中,官方称为Displaced Mark Word。然后线程尝试使用
CAS将对象头中的Mark Word替换为指向锁记录的指针。如果成功,当前线程获得锁,如果失
败,表示其他线程竞争锁,当前线程便尝试使用自旋来获取锁。

(2)轻量级锁解锁

轻量级解锁时,会使用原子的CAS操作将Displaced Mark Word替换回到对象头,如果成
功,则表示没有竞争发生。如果失败,表示当前锁存在竞争,锁就会膨胀成重量级锁。图2-2是
两个线程同时争夺锁,导致锁膨胀的流程图。

因为自旋会消耗CPU,为了避免无用的自旋(比如获得锁的线程被阻塞住了),一旦锁升级
成重量级锁,就不会再恢复到轻量级锁状态。当锁处于这个状态下,其他线程试图获取锁时,
都会被阻塞住,当持有锁的线程释放锁之后会唤醒这些线程,被唤醒的线程就会进行新一轮
的夺锁之争。
在这里插入图片描述
什么是CAS操作
参看如下:
https://blog.youkuaiyun.com/qq_37937537/article/details/82798218

3.锁的优缺点对比
在这里插入图片描述
2.3 原子操作的实现原理
原子(atomic)本意是“不能被进一步分割的最小粒子”,而原子操作(atomic operation)意
为“不可被中断的一个或一系列操作”。

在多处理器上实现原子操作就变得有点复杂。

通信编程之java socket【二】-持续通信和多线程通信 上一节讲到java socket的服务端和客户端的简单通信,了解到socket的通信机制,详见:通信编程之java socket初探 今天我们继续深入一下,之前的例子有一个问题,就是只能发送一次消息就结束了,我们知道微信、QQ都是持续的收发消息的,那我们怎么才能使客户端持续的发送消息呢?下面我们就来实战探讨下。 一、java socket怎么持续通信 socket的服务端是阻塞式的通信的,通过accept()方法来阻塞,等待客户端的连接,连接后客户端发送消息,通过IO来收发消息。从这个流程上来看,我们 阅读详情

相关推荐

华中科技大学计算机组成原理-单总线CPU设计(全部通关)

【计算机组成原理】 单总线CPU实验 华中科技大学-计算机组成原理 实验三 单总线CPU设计 第1关 MIPS指令译码器设计 第2关 单总线CPU微程序入口查找逻辑 第3关 单总线CPU微程序条件判别测试逻辑 第4关 单总线CPU微程序控制器设计 第5关 采用微程序的单总线CPU设计 第6关 现代时序硬布线控制器状态机设计 第7关 现代时序硬布线控制器设计

紫荆鱼的博客 4万+

树形动态规划之树的最大独立集

树的最大独立集 对于一颗n个结点的无根树,选出尽量多的的结点,使得任何两个结点均不相邻(称为最大独立集),然后输入n-1条无向边,输出一个最大独立集(如果有多解,则任意输出一组)。 分析: 用d(i)表示以i为根结点的子树的最大独立集的大小。此时需要注意的是,本题的树是无根的:没有所谓的父子关系,而只是一些无向边。没关系,只要任选一个跟r,无根树就变成了有根树,上述状态的定义也就有意义了。

RoundYuan 2275

liquibase介绍

1、Liquibase还是Flyway Flyway和Liquibase都支持专业数据库重构和版本控制所需的所有功能,因此您将始终知道要处理的数据库模式的版本以及它是否与软件版本匹配。两种工具都集成在Maven或Gradle构建脚本中以及Spring Boot生态系统中,因此您可以完全自动化数据库重构。 Flyway使用SQL定义数据库更改,因此您可以定制SQL脚本,使其与基础数据库技术(例如Oracle或PostgreSQL)良好地配合使用。另一方面,使用Liquibase,您可以通过使用XML,YA

赶路人儿 7533

JAVA多线程——(二)多线程编程

JAVA多线程——(二)多线程编程 文章目录JAVA多线程——(二)多线程编程【一】ReentrantLock【二】ReadWriteLock【三】Condition【四】Concurrent集合【五】Atomic【六】ExecutorService【七】CountDownLatch【八】Volatile【九】ThreadLocal【十】链接 【一】ReentrantLock 【二】ReadWri...

wenge1477的博客 315

MicroPython ubluetooth 库详细介绍

MicroPython的ubluetooth库为蓝牙通信提供了强大的支持,使得开发者能够在MicroPython环境下轻松实现蓝牙设备之间的通信。其中ubluetooth库为MicroPython提供了强大的蓝牙通信功能,使得开发者能够轻松地在各种支持MicroPython的硬件平台上实现蓝牙设备之间的通信。它提供了一系列的函数和类,用于实现蓝牙设备的扫描、连接、数据传输等功能。- 上述代码中,首先创建了一个蓝牙服务和一个特征,然后可以通过read和write函数读取和写入特征值。# 处理连接成功事件。

m0_46311182的博客 1761

别再只抄代码了!深入理解MQ2传感器数据手册,搞定ppm换算公式

本文深入解析MQ2烟雾传感器的工作原理与ppm换算公式,从数据手册解读到数学建模,提供详细的校准与优化方法。通过实际案例和代码示例,帮助开发者准确测量气体浓度,解决常见问题,提升传感器应用的可靠性。

weixin_42713608的博客 504

JAVA多线程编程陷阱总结二

陷阱7:正确使用静态同步方法 Java语言规定:任何线程进入同步方法,同步代码块之前,必须先获取同步方法,同步代码块对应的同步监视器。对于同步代码块而言,程序必须显示为它指定同步监视器;对于同步非静态方法而言,该方法的同步监视器是this-即调用该方法的Java对象;对于静态的同步方法而言,该方法的同步监视器不是this,而是该类本身。 class SynchronizedStatic i

guomei的专栏 703

SRAM compiler中Power Gating与Retention的实战配置指南

本文深入解析了在SRAM compiler中配置Power Gating(电源门控)与Retention(数据保持)功能的实战指南。针对低功耗芯片设计,文章详细阐述了如何根据应用场景(如移动AP、IoT设备)权衡开关类型、尺寸、唤醒时序以及保持电压,以实现静态功耗优化与数据可靠性的最佳平衡,并强调了后端实现与签核检查的关键要点。

weixin_29204121的博客 294

Java多线程编程(二)

在Java多线程编程(一) 中的多线程并没有返回值,本文将介绍带返回值的多线程。 要想有返回值,则需要实现新的接口Callable而不再是Runnable接口,实现的方法也改为call()方法,执行器也不再是调用execute(),而是submit() 【程序实例】 1 public class TaskWithResult implements Callable<S...

dhu86380的博客 95

速腾聚创激光雷达复现FAST-LIO

记录复现FAST-LIO算法的过程和,代码梳理和理解。FAST-LIO的简化版、注释版。速腾激光雷达

abanchao的博客 2928

YOLO11改进|卷积篇|引入SPDConv

YOLO11中添加SPDConv卷积

A1983Z的博客 3696

java的多线程编程二

看过上篇文章的应该知道如果想实现一个生产者消费者模型,我们可以基于JVM自带的synchronized+wait+notify实现,也可以用JDK里面的ReentrantLock+Condition实现!不过从上篇文章的demo看,实现起来也不是那么容易!因为我们既要关心什么时候需要阻塞线程,又要需要关心何时唤醒线程。控制的细节太多,一个疏忽可能就导致了一个不易发现的bug,比如上篇文章中的虚假唤醒的例子!那有没有一种我们不用关心那么多复杂细节就能实现生产者消费者模式的方法呢?

s44359487yad的博客 1041

2026.3.13:docker compose运行了Milvus 6个月,占用磁盘近138GB的原因

Docker容器运行Milvus半年后占用138GB磁盘空间,主要原因是容器日志无限增长、容器内写入大量数据未挂载到数据卷,以及未清理临时文件。通过检查发现超大容器目录569035582ce3...占用主要空间。解决方案是使用truncate命令清空容器日志文件(*-json.log),释放磁盘空间。建议配置日志轮转机制,并将数据挂载到宿主机数据卷以避免类似问题。

拥抱具身智能,昇腾Ascend C 194

Java基础(二) 多线程编程

一个线程不能独立存在,它必须生存在某个进程中,而一个进程可以有多个线程执行。线程是进程中的一个任务流。一个Java程序不能每次只服务一个用户,可能有很多用户同时请求进程,进程就不得不创建多个线程来响应用户请求。

这里是阿安的博客 512

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

Java中的多线程编程(二)

线程同步处理     多线程编程的目的是提高资源利用率和缩短系统的响应时间,它的特征是多个线程并发执行。有时候在进行多线程的程序设计中需要实现多个线程共享同一段代码,从而实现共享同一个私有成员或类的静态成员的目的。这时,由于线程与线程之间相互竞争CPU资源,使得线程无序的访问这些共享资源,可能导致结果不正确。 一、同步代码块    Java虚拟机为每个对象配备一把锁和一个等候集,这个对象可以

gerks的博客 495

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

【Java】多线程编程(二)

这里宽泛地写了Java高并发的 阻塞队列 和 线程池 重要内容,图文有加,有利于大家在java并发学习中全面了解。

Frms的博客 1113

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

Java高级编程--多线程(二)

多线程程序将单个任务按照功能分解成多个子任务来执行,每个子任务称为一个线程,多个线程共同完成主任务的运行过程,这样可以缩短用户等待时间,提高服务效率。本篇博客将继续介绍Java开发中多线程的使用。

༺ཌ༈君纤༈ད༻ 340

java---多线程编程二

java并发和jvm如何支持并发

m0_58342797的博客 418

【Java并发编程二】解决多线程安全问题的方法

我们使用多线程就好比一群滑稽老铁坐在同一张桌子前吃鸡,此时1号滑稽和2号滑稽同时看上了同一只鸡,1号滑稽碰到了鸡翅,2号滑稽碰到了鸡腿, 结果整只鸡被1号滑稽抢走了,此时二号滑稽就会非常生气(出现异常),可能会直接掀桌子(使整个进程被终止)。正常来说,按照锁的特性这个时候会出现死锁的情况,因为只有这个线程结束才能释放锁,而第二次加锁会使线程一直堵塞,无法结束,第二个锁无法得到锁对象永远无法解锁,陷入死循环。一个是用于线程之间的通信的,一个是让线程阻塞一段时间,唯一的相同点就是都可以让线程放弃执行一段时间。

2203_75565612的博客 957

Java 多线程并发编程(二) -总结

Java 多线程并发编程(二) 1、并发编程三要素? 原子性: 原子性指的是一个或者多个操作,要么全部执行并且在执行的过程中不被其他操 作打断,要么就全部都不执行。 可见性: 可见性指多个线程操作一个共享变量时,其中一个线程对变量进行修改后,其他 线程可以立即看到修改的结果。 有序性: 有序性即程序的执行顺序按照代码的先后顺序来执行。 2、实现可见性的方法有哪些? synchronized 或者 Lock:保证同一个时刻只有一个线程获取锁执行代码,锁释放 之前把最新的值刷新到主内存,更或者volati

精◈彩◈猿◈笔◈记 250

Java 多线程抢占 编程_Java-多线程并发编程二(完结)

Java多线程并发编程线程的挂起与恢复(wait、notify、notifyAll)package Thread;/*** @ProjectName: WaitDemo* @Package: Thread* @Description:* @Author: huyuqiao* @CreateDate: 2020/10/16 10:20*/public class WaitDemo implement...

weixin_39854070的博客 142

实战体会Java多线程编程(二)

synchronized 关键字到目前为止,我们看到的示例都只是以非常简单的方式来利用线程。只有最小的数据流,而且不会出现两个线程访问同一个对象的情况。但是,在大多数有用的程序中,线程之间通常有信息流。试考虑一个金融应用程序,它有一个 Account 对象,如下例中所示:一个银行中的多项活动public class Account {    String holderName;  

leagle 953

Java 从多线程到并发编程(二)——Runnable Callable

- 继上一次我们初识了线程 进程 多线程等概念,也学会使用继承Thread类的方式来实现多线程 - 本节将会帮助你了解... - 实现Runnable接口的方式 实现多线程效果 - 实现Callable接口的方式 实现多线程效果

菜鸡的学习之路 2790

Java并发编程-多线程基础(二)

Java并发编程之线程状态

gdr12的专栏 1379

java基础知识②:多线程编程、IO流和网络编程、泛型、集合框架

多线程编程、IO流和网络编程、泛型、集合框架

两点 1916
上一篇: java多线程编程(一)
下一篇: java多线程编程(三)
Round_Yuan
博客等级 码龄10年 26粉丝 78原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值