首页 文章 精选 留言 我的

精选列表

搜索[java8],共826篇文章
优秀的个人博客,低调大师

探究synchronized底层原理(基于JAVA8源码分析)

JVM支持方法级和方法内部一段指令序列的同步,都用同步锁(monitor)实现 synchronized可以保证方法或者代码块在运行时,同一时刻只有一个方法可以进入临界区,同时它还可以保证共享变量的内存可见性 Java中每一个对象都可以作为锁,这是synchronized实现同步的基础 1. 普通同步方法,锁是当前实例对象 2. 静态同步方法,锁是当前类的class对象 3. 同步方法块,锁是括号里面的对象 当一个线程访问同步代码块 首先得到锁才能执行同步代码 当退出或者抛异常时必须释放锁 如何来实现这个机制呢? 实现原理 看一段简单的代码 生成的class文件信息 JVM的同步(synchronization)是monitor的进入和退出实现的,无论是显式同步(有明确的monitorenter和monitorexit指令),还是隐式同步(无需通过字节码指令控制,依赖方法调用和返回指令实现) Java中,同步用的最多的可能就是经synchronized修饰的同步方法 同步方法并不是用monitorenter和monitorexit实现的,而是由方法调用指令读取运行时常量池中方法的ACC_SYNCHRONIZED标志来隐式实现的0 .monitorenter和monitorexit指令用于编译synchronized同步0.语句块 JVM从方法常量池中的方法表结构中的ACC_SYNCHRONIZED访问标志区区分是否为同步方法 调用时,调用指令将会检查方法的ACC_SYNCHRONIZED是否设置,是则执行线程将先获得同步锁,然后执行方法,最后完成方法时释放同步锁 执行期间,其他线程都无法获得同一个锁,若运行期间抛异常并且方法内部无法处理时,所持有的锁将在抛异常到同步方法之外时自动释放 同步代码块 monitorenter插入到同步代码块的开始位置monitorexit插入到结束位置 JVM需要保证每一个monitorenter都有一个monitorexit对应 任何对象都有一个monitor与之关联,且当一个monitor被持有之后,他将处于锁定状态 线程执行到monitorenter时,将会尝试获取对象的monitor所有权,即尝试获取对象的锁 同步方法 synchronized方法会被翻译成普通的方法调用和返回指令如:invokevirtual、areturn指令 在JVM字节码层面并没有任何特别的指令来实现被synchronized修饰的方法, 而是在Class文件的方法表中将该方法的access_flags字段中的synchronized标志位 置1,表该方法是同步方法并使用调用该方法的对象或该方法所属的Class在JVM的内部对象表示Klass做为锁对象 深入之前我们需要了解两个重要的概念:Java对象头,Monitor。 Java对象头 synchronized用的锁存在Java对象头 对象头主要包括 Klass Pointer(类型指针) 对象指向它的类元数据的指针 JVM通过该指针确定该对象是何类的实例 Mark Word(标记字段) 存储对象的运行时数据 是实现轻量级锁和偏向锁的关键 Mark Word 存储对象自身的运行时数据,如哈希码、GC分代年龄、锁状态标志、线程持有的锁、偏向线程 ID、偏向时间戳等 Java对象头一般占有两个机器码(在32位虚拟机中,1个机器码等于4字节,也就是32bit),但是如果对象是数组类型,则需要三个机器码,因为JVM虚拟机可以通过Java对象的元数据信息确定Java对象的大小,但是无法从数组的元数据来确认数组的大小,所以用一块来记录数组长度 Java对象头的存储结构(32位VM) 对象头信息是与对象自身定义的数据无关的额外存储成本,但是考虑到虚拟机的空间效率,Mark Word被设计成一个非固定的数据结构以便在极小的空间内存存储尽量多的数据,它会根据对象的状态复用自己的存储空间,也就是说,Mark Word会随着程序的运行发生变化,变化状态如下(32位虚拟机): Monitor 可以把它理解为一个同步工具,也可以描述为一种同步机制,它通常被描述为一个对象。 和万物皆对象一样,所有的Java对象是天生的Monitor,每一个Java对象都有成为Monitor的潜质,因为在Java的设计中 ,每一个Java对象自打娘胎里出来就带了一把看不见的锁,它叫做内部锁或者Monitor锁 Monitor 是线程私有的数据结构,每一个线程都有一个可用monitor record列表,同时还有一个全局的可用列表。 每一个被锁住的对象都会和一个monitor关联(对象头的MarkWord中的LockWord指向monitor的起始地址),同时monitor中有一个Owner字段存放拥有该锁的线程的唯一标识,表示该锁被这个线程占用。其结构如下 Owner:初始时为NULL表示当前没有任何线程拥有该monitor record,当线程成功拥有该锁后保存线程唯一标识,当锁被释放时又设置为NULLEntryQ:关联一个系统互斥锁(semaphore),阻塞所有试图锁住monitor record失败的线程RcThis:表示blocked或waiting在该monitor record上的所有线程的个数Nest:用来实现重入锁的计数HashCode:保存从对象头拷贝过来的HashCode值(可能还包含GC age)Candidate:用来避免不必要的阻塞或等待线程唤醒,因为每一次只有一个线程能够成功拥有锁,如果每次前一个释放锁的线程唤醒所有正在阻塞或等待的线程,会引起不必要的上下文切换(从阻塞到就绪然后因为竞争锁失败又被阻塞)从而导致性能严重下降。Candidate只有两种可能的值0表示没有需要唤醒的线程1表示要唤醒一个继任线程来竞争锁。

优秀的个人博客,低调大师

Eurynome Cloud 2.7.0.60 发布,升级SAS 0.3.1,降级兼容Java8

Eurynome Cloud 是一款企业级微服务架构和服务能力开发平台。首个全面拥抱 Spring Authorization Server 的版本,基于Spring Boot 2.7.0、Spring Cloud 2021.0.3、Spring Cloud Alibaba 2021.0.1.0、 Spring Authorization Server 0.3.1、Nacos 2.1.0 等最新版本开发,遵循SpringBoot编程思想,高度模块化和可配置化。具备服务发现、配置、熔断、限流、降级、监控、多级缓存、分布式事务、工作流等功能 平台定位 构建成熟的、完善的、全面的,基于 OAuth2 的、前后端分离的微服务架构解决方案。 面向企业级应用和互联网应用设计开发,既兼顾传统项目的微服务化,又满足互联网应用开发建设、快速迭代的使用需求。 平台架构使用微服务领域及周边相关的各类新兴技术或主流技术进行建设,是帮助快速跨越架构技术选型、研究探索阶段的利器。 代码简洁规范、结构合理清晰,是新技术开发应用的典型的、综合性案例,助力开发人员对新兴技术的学习和掌握。 [1]、发布背景 2021年11月8日 Spring 官方已经强烈建议使用 Spring Authorization Server 替换已经过时的 Spring Security OAuth2.0。 在 Spring Security OAuth2 彻底停止维护、Spring Boot 2.7.0 正式发布之时,又恰逢 Eurynome Cloud 开源一周年之际,推出基于 Spring Authorization Server 0.3.0、Spring Boot 2.7.0、Spring Cloud 2021.0.3、Spring Cloud Alibaba 2021.0.1.0 和 Nacos 2.1.0 的全新正式版本,细节满满,欢迎品鉴。 [2]、重要说明 由于 Spring Authorization Server 0.3.0 版本,使用 Java 11 进行代码编译。导致使用该版本在 Java 8 下代码已无法编译成功,所以必须要升级 JDK 版本。同时,考虑到 2022 年 11 月,Spring Boot 3 将会发布,最低版本要求 Java 17。因此,直接将 Java 版本升级至 17。Eurynome Cloud 2.7.0.20 ~ 2.7.0.50 均是采用 Java 17 编译运行,同时不兼容 Java 8。 不管是 Spring Authorization Server 还是本项目 Eurynome Cloud,各路网友均不主张在现阶段直接将 Java 升级 17,而是希望继续兼容 Java 8,在 Spring Boot 3 发布以后再统一升级为默认使用 Java 17 因此 Spring Authorization Server 0.3.1 版本,代码降级兼容了 Java 8。Eurynome Cloud 也同步进行了代码的降级兼容处理,以兼容 Java 8。经过验证,目前 Erurynom Cloud 在 Java 8、11、17 环境下均可以正常稳定运行 Spring Authorization Server 发布两个版本,Eurynome Cloud 使用的 Java 版本就跟着变,升到 Java 17 又跟着降回 Java 8,折腾一圈浪费功夫。看似折腾实则不然,经此一役,Eurynome Cloud 已经完全支持 Java 8 Java 11 和 Java 17,未来升级使用 Spring Boot 3 也不是问题。验证了那句话“用心认真走过的每条路都不会白走” [3]、本次更新内容 重要更新 Spring Authorization Server 版本升级至 0.3.1 系统使用 Java 版本降级兼容 Java 8,经验证目前本系统在 Java 8、11、17 环境下均可以正常稳定运行。 其它更新 [修复] 修复人员归属管理功能中,删除已配置人员归属会出现 Jackson 反序列化问题。 [优化] 优化单位树和部门树,树形数据组织代码,对不同类型的根节点数据,统一处理为系统定义标准根节点,便于前端组件使用和封装。 [优化] 优化社交登录接口相关代码,同时增加 @Inner 注解,解决该接口内部调用跳过权限验证问题。 [优化] 优化自定义 OAuth2 Security 权限元数据管理接口相关代码 [重构] 重构权限表达式枚举类代码,与系统已有枚举常量体系统一。调整该类所在包,便于前端将其常量使用。 [删除] Spring Security 5.7.0 版本以前,Spring Security WebAuthenticationDetails 类只支持 HttpServletRequest 做为参数,这导致无法在 Spring Security 自身的登录页面增加验证码等额外信息。因此,提取了 WebAuthenticationDetails 代码进行扩展,以支持登录验证码功能。随着 Spring Security 的版本升级至 5.7.1,该问题已经被修复,因此删除原有自行扩展代码。 依赖更新 OkHttp 版本升级至 4.10.0 [4]、Eurynome Cloud 2.7.X 主要变化 基于 Spring Authorization Server 深度定制: 基于 Spring Data JPA,重新构建 Spring Authorization Server 基础数据存储代码,替代原有 JDBC 数据访问方式,破除 Spring Authorization Server 原有数据存储局限,扩展为更符合实际应用的方式和设计。 基于 Spring Authorization Server,在 OAuth 2.1 规范基础之上,增加自定义“密码”认证模式,以兼容现有基于 OAuth 2 规范的、前后端分离的应用。 基于 Spring Authorization Server,在 OAuth 2.1 规范基础之上,增加自定义Social Credentials 认证模式,支持手机短信验证码、微信小程序、第三方应用登录。 遵照 Spring Security 5 以及 Spring Authorization Server 的代码规范,进行 OAuth2 认证服务器核心代码的开发,遵照其使用 Jackson 反序列化的方式, 增加大量自定义 Jackson Module。 支持 Spring Authorization Server 的标准的Token加密校验方式外,还了增加支持自定义证书的 Token 加密方式,可通过配置动态修改 支持 OAuth2 OIDC 认证模式,补充前端 OIDC 认证相关配置操作,以及对应的 /userinfo 接口调用支持 和 客户端注册支持 支持 OAuth2 Authorization Code PKCE 认证模式 扩展 Spring Authorization Server 默认的 Client Credentials 模式,实现 Refresh Token 的创建。 扩展 Spring Authorization Server 默认的 Client Credentials 模式,实现真正的使用 Scope 权限对接口进行验证。 增加客户端 Scope 的权限配置功能,并与已有的用户权限体系解耦 自定义 Spring Authorization Server 授权码模式登录认证页面和授权确认页面,授权码模式登录采用数据加密传输。支持多种验证码类型,暂不支持行为验证码。 代码结构的大规模调整和优化: 对原有代码进行了深度的“庖丁解牛”,严格遵照“单一职责”原则,根据各个组件的职责以及用途,将整个工程拆解细化为多个各自独立组件模块,在最大程度上降低代码间的耦合,也更容易聚焦和定位问题。 将通用化组件提取为独立工程,独立编译、按需选用,极大的降低系统主工程代码量。相关组件也已上传至 Maven 中央仓库,降低系统主工程工程代码编译耗时,改进和提升 CICD 效率, 原有主工程代码结构也进行了深化调整,代码分包更加合理,代码逻辑也更加清晰。 [5]、额外说明 本项目以后将主要维护 Spring Authorization Server 版本,原有基于 Spring Security OAuth2 的版本已经移至 spring-security-oauth2 分支,可以从该分支或发行版页面获取历史版本继续使用。后期会根据 ISSUE 以及使用用户反馈情况,再行决定是否继续维护 Spring Security OAuth2 版本。 最新版本代码,暂时继续沿用原有基于 Vue2、Vuetify2、Typescript开发的前端系统。基于 Vue3、Vite2、Quasar、Pinia、Typescript的新版前端正在加进开发中,预计本月底发布。 原有基于 Vue2、Vuetify2、Typescript 开发的前端,由于使用了过渡性 Typescript IOC 组件,以及依赖组件版本限制等问题,初次接触该项目在编译过程中会出现一些问题,请移步至本项目在线文档,详见“常见问题”章节。

优秀的个人博客,低调大师

Java8如何让Excel的读写变得更加简单高效

在POI的使用过程中,对大多数API User来说经常面临两个问题,这也是 GridExcel 致力解决的问题。 问题1. 仅使用简单的导入导出功能,但每次业务的数据对象结构不同,需要重新编写处理方法,很麻烦!解决方法将Excel处理逻辑抽取出来,封装成工具类。 封装条件与大多数Java API一样,POI把更多的精力放在高级功能的处理上,比如Formula(公式)、Conditional Formatting(条件格式)、Zoom(缩放)等。对于仅仅做数据导入导出功能的API User,很少使用这些高级特性,这允许API用户对POI的使用进行简单的封装。 封装方式无论是读是写,我们都需要解决Excel中的Columns(列)与Java数据对象Fields(字段)的映射关系,将这种映射关系作为参数(Map对象HashMap或LinkedHashMap),传递给工具类。 对于Columns不难理解,它可以是有序的数字或字母,也可以是其它字符串用来作为首行,表示该列数据的含义。 对于Fields,它的处理需要兼容复杂情况,如下: value == true?完成:失败;反射首先想到,也是大多数封装者都在使用的方式是就是 Reflection API ,从上文 函数编程 章节我们了解到,反射重量级,会降低代码的性能,同时对复杂情况的处理支持性不够好。 反射+注解这种方式可以更好的支持复杂情况,但是反射依然会降低性能,同时注解对数据对象会造成代码侵入,而且对该工具类封装者的其他使用者无疑会增加学习成本。 匿名内部类这种方式也可以很好的支持复杂情况,但是使用匿名内部类的语法显然患有“垂直问题”(这意味着代码需要太多的线条来表达基本概念),太过冗杂。 至于性能,应该也不如直接传递函数来的快吧。 函数接口(Lambda)这种方式是基于第5条方法调用的字节码指令 invokeDynamic 实现的,直接传递函数代码块,很好的支持复杂情况,性能较高,代码编写更简单结构更加简洁,而且对数据对象代码零侵入。 当然如果你还没有使用Java1.8或更高版本,那么你可以参考 匿名内部类 或 反射+注解 ,不过还是推荐 反射+注解 , Alibaba/easyexcel【https://github.com/alibaba/easyexcel】 对你来说会是不错的选择。 问题2. Excel导入或导出数据量比较大,造成 内存溢出 或 频繁的Full GC ,该如何解决?解决方法读Excel —— eventmodel写Excel —— streaming.SXSSFWorkbook原理POI的使用对我们来说很常见,对下面两个概念应该并不陌生: HSSFWorkbook(处理97(-2007) 的.xls)XSSFWorkbook(处理2007 OOXML (.xlsx) )但是对于 eventmodel 和 streaming.SXSSFWorkbook 就很少接触了,它们是POI提供的专门用来解决内存占用问题的 low level API (低级API),使用它们可以读写数据量非常大的Excel,同时可以避免 内存溢出 或 频繁的Full GC 。【 https://poi.apache.org/components/spreadsheet/how-to.html】 eventmodel ,用来读Excel,并没有将Excel整个加载到内存中,而是允许用户从 InputStream 每读取一些信息,就交给 回调函数 或 监听器 ,至于丢弃,存储还是怎么处理这些内容,都交由用户。streaming.SXSSFWorkbook ,用来写Excel(是对XSSFWorkbook的封装,仅支持.xlsx),通过 滑动窗口 来实现,只在内存中保留滑动窗口允许存在的行数,超出的行Rows被写出到临时文件,当调用 write(OutputStream stream) 方法写出内容时,再直接从临时内存写出到目标 OutputStream 。 SXSSFWorkbook 的使用会产生一些局限性。Only a limited number of rows are accessible at a point in time.Sheet.clone() is not supported.Formula evaluation is not supported 解决途径https://github.com/liuhuagui/gridexcel 基于Java函数编程(Lambda),支持流式API,使用环境Java1.8或更高,学习成本:Lambdahttps://github.com/alibaba/easyexcel 基于反射+注解+监听器,使用环境Java1.6或以上,学习成本:模型注解实际上POI官网已经给了用户使用示例,而上述两个工具都只是做了自己的封装实现,使用者只需要拿来用就好。 快速使用 <groupId>com.github.liuhuagui</groupId> <artifactId>gridexcel</artifactId> <version>2.2</version> GridExcel.javaGridExcel.java提供了多种静态方法,可以直接使用,具体式例可参考测试代码(提供了测试数据和测试文件): https://github.com/liuhuagui/gridexcel/blob/master/src/test/java/ReadTest.javahttps://github.com/liuhuagui/gridexcel/blob/master/src/test/java/WriteTest.java流式API/** 业务逻辑处理方式三选一: 1.启用windowListener,并将业务逻辑放在该函数中。 2.不启用windowListener,使用get()方法取回全部数据集合,做后续处理。 3.readFunction函数,直接放在函数中处理 或 使用final or effective final的局部变量存放这写数据,做后续处理。 注意:使用EventModel时readFunction函数的输入为每行的cell值集合List。 @throws Exception*/ @Test public void readXlsxByEventModel() throws Exception { InputStream resourceAsStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("2007.xlsx"); GridExcel.readByEventModel(resourceAsStream,TradeOrder.class,ExcelType.XLSX) .window(2,ts -> System.out.println(JSON.toJSONString(ts)))//推荐在这里执行自己的业务逻辑 .process(cs ->{ TradeOrder tradeOrder = new TradeOrder(); tradeOrder.setTradeOrderId(Long.valueOf(cs.get(0))); Consultant consultant = new Consultant(); consultant.setConsultantName(cs.get(3)); tradeOrder.setConsultant(consultant); tradeOrder.setPaymentRatio(cs.get(16)); return tradeOrder; },1); } /** 使用Streaming UserModel写出数据到Excel @throws Exception*/ @Test public void writeExcelByStreaming() throws Exception { GridExcel.writeByStreaming(TradeOrder.class) .head(writeFunctionMap())//对象字段到Excel列的映射 .createSheet() .process(MockData.data())//模拟数据。在这里设置业务数据集合。 .write(FileUtils.openOutputStream(new File("/excel/test.xlsx"))); }ReadExcelReadExcelByUserModelUse user model to read excel file. userModel —— 缺点 :内存消耗大,会将excel信息全部加载到内存再进行处理。优点 :现成的API,使用和理解更简单。使用场景 :可以处理数据量较小的Excel。ReadExcelByEventModelUse event model to read excel file. eventModel —— 缺点 :没有现成的API,使用和理解较为复杂,适合中高级程序员(GridExcel的目标之一就是让EventModel的使用变得简单)优点 :非常小的内存占用,并没有在一开始就将所有内容加载到内存中,而是把主体内容的处理(存储,使用,丢弃)都交给了用户,用户可以自定义监听函数来处理这些内容。使用场景 :可以处理较大数据量的Excel,避免OOM和频繁FullGCWriteExcelWriteExcelByUserModelUse user model to write excel file. userModel —— 缺点 :会将产生的spreadsheets对象整个保存在内存中,所以write Excel的大小受到堆内存(Heap space)大小限制。优点 :使用和理解更简单。使用场景 :可以写出数据量较小的Excel。WriteExcelByStreamingUse API-compatible streaming extension of XSSF to write very large excel file. streaming userModel—— 缺点 :仅支持XSSF;Sheet.clone() is not supported;Formula evaluation is not supported;Only a limited number of rows are accessible at a point in time. 优点 :通过滑动窗口来实现,内存中只保留指定size of rows的内容,超出部分被写出到临时文件,write Excel的大小不再受到堆内存(Heap space)大小限制。使用场景 :可以写出非常大的Excel。Issues在使用工具过程中出现问题,有功能添加或改动需求的可以向作者提Issue: https://github.com/liuhuagui/gridexcel/issues 比如说,想要增加对首行以外的行列做样式扩展 需要java学习路线图的私信笔者“java”领取哦!另外喜欢这篇文章的可以给笔者点个赞同,关注一下,每天都会分享Java相关文章!还有不定时的福利赠送,包括整理的学习资料,面试题,源码等~~

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册