首页
Bilibili
GitHub
友链
留言
相册
更多
归档
Search
1
MybatisPlus的坑( 自动驼峰命名)
115 阅读
2
欢迎来到ZzRGd的博客
59 阅读
3
初识JAVA及特性
56 阅读
4
解决Idea中注入Mapper警告的6个方法!
54 阅读
5
配置文件YAML基本语法
52 阅读
👋活在当下
🥇学习
WEB前端
CSS
JavaScript
JAVA
登录
/
注册
Search
标签搜索
JAVA
Spring Boot
笔记
学习
锁
JUC
Git
仓库
MySql
Mybatis
Mybatis-Plus
踩雷
高并发
spring cloud
Gateway
分布式
ZzRG
累计撰写
25
篇文章
累计收到
1
条评论
首页
栏目
👋活在当下
🥇学习
WEB前端
CSS
JavaScript
JAVA
页面
Bilibili
GitHub
友链
留言
相册
归档
搜索到
16
篇与
的结果
2022-12-27
分布式锁Mysql篇
分布式锁CREATE TABLE `stock` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `product_code` varchar(20) NOT NULL, `warehouse` varchar(20) NOT NULL, `count` int(11) NOT NULL, PRIMARY KEY (`id`), KEY `idx_pc` (`product_code`) ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;1.JVM本地锁2.一个sql3.悲观锁:select ...from updatemysql悲观锁中使用行级锁:1.锁的查询或者更新条件必须是索引字段 2.查询或者更新条件必须是具体值 不能使用 like这样的模糊查询Mapper代码实现:@select("select * from stock where product_code = #{productCode} for update;") List<Stock> queryStock(String productCode);service实现:解决了锁定的范围 同时一个商品的多条库存记录 记录了库存变化前后的状态缺点问题: 1.性能问题 性能较低2.会产生死锁: 对多条数据加锁时,加锁的顺序要一致 3.库存操作要统一:用select ...for update 而用普通select锁不住4.mysql的乐观锁:时间戳version版本号CAS机制CREATE TABLE `stock` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `product_code` varchar(20) NOT NULL, `warehouse` varchar(20) NOT NULL, `count` int(11) NOT NULL, `version` int(11) NOT NULL, PRIMARY KEY (`id`), KEY `idx_pc` (`product_code`) ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;如果version与mysql中的不相等就更新失败 再次进行尝试!servic实现:会出现栈溢出 还有超时问题!解决栈溢出问题MDL 更新删除操作 会进行加锁 就会出现超时问题去掉手动事务@Transactional(事务也会加锁) 后面当进行到 if(this....update...)时候 本来有悲观锁 当执行失败的就会放掉锁 后面就不会阻塞 最终:乐观锁存在的问题:1.高并发的情况下,性能极低。 (乐观锁适合读多写少的情况)2.CAS会产生ABA问题。3.读写分离的情况下导致乐观锁不可靠myqsl锁总结:性能:一个sql>悲观锁>JVM锁>乐观锁如果追求极致的性能,业务场景简单并不需要记录前后变化的情况下 优先选择:一个sql;如果写并发量低(读多),争抢不是很激烈的情况下 优先选择:乐观锁;如果写并发量较高,一般会经常冲突,此时选择乐观锁的话,会导致业务代码间的不断重试。 应该优先选择:悲观锁;不推荐使用JVM本地锁;
2022年12月27日
12 阅读
0 评论
0 点赞
2022-11-21
微服务网关Gateway使用
微服务网关Gateway使用为什么需要网关?Gateway网关是我们服务的守门神,所有微服务的统一入口。网关的核心功能特性1. 请求路由和负载均衡 一切请求都必须先经过gateway,但网关不处理业务,而是根据某种规则,把请求转发到某个微服务,这个过程叫做路由。当然路由的目标服务有多个时,还需要做负载均衡。2. 权限控制 网关作为微服务入口,需要校验用户是是否有请求资格,如果没有则进行拦截。3. 限流 请求流量过高时,在网关中按照下流的微服务能够接受的速度来放行请求,避免服务压力过大。架构图gateway快速入门基本步骤如下:1、创建SpringBoot工程gateway,引入网关依赖<!--网关--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <!--nacos服务发现依赖--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency>2、编写启动类package com.cn.gateway; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class GatewayApplication { public static void main(String[] args) { SpringApplication.run(GatewayApplication.class, args); } }3、编写基础配置和路由规则server: port: 10010 # 网关端口 spring: application: name: gateway # 服务名称 cloud: nacos: server-addr: localhost:8848 # nacos地址 gateway: routes: # 网关路由配置 - id: user-service # 路由id,自定义,只要唯一即可 # uri: http://127.0.0.1:8081 # 路由的目标地址 http就是固定地址 uri: lb://userservice # 路由的目标地址 lb就是负载均衡,后面跟服务名称 predicates: # 路由断言,也就是判断请求是否符合路由规则的条件 - Path=/user/** # 这个是按照路径匹配,只要以/user/开头就符合要求 我们将符合Path 规则的一切请求,都代理到 uri参数指定的地址。本例中,我们将 /user/** 开头的请求,代理到lb://userservice,lb是负载均衡,根据服务名拉取服务列表,实现负载均衡。4、启动网关服务进行测试重启网关,访问 http://localhost:10010/user/1 时,符合/user/**规则,请求转发到uri:http://userservice/user/15、网关路由的流程图总结网关搭建步骤创建项目,引入nacos服务发现和gateway依赖配置application.yml,包括服务基本信息、nacos地址、路由路由配置包括路由id:路由的唯一标识路由目标(uri):路由的目标地址,http代表固定地址,lb代表根据服务名负载均衡路由断言(predicates):判断路由的规则,路由过滤器(filters):对请求或响应做处理路由断言和路由过滤器断言工厂名称说明示例After是某个时间点后的请求- After=2037-01-20T17:42:47.789-07:00[America/Denver]Before是某个时间点之前的请求- Before=2031-04-13T15:14:47.433+08:00[Asia/Shanghai]Between是某两个时间点之前的请求- Between=2037-01-20T17:42:47.789-07:00[America/Denver], 2037-01-21T17:42:47.789-07:00[America/Denver]Cookie请求必须包含某些cookie- Cookie=chocolate, ch.pHeader请求必须包含某些header- Header=X-Request-Id, \d+Host请求必须是访问某个host(域名)- Host=.somehost.org,.anotherhost.orgMethod请求方式必须是指定方式- Method=GET,POSTPath请求路径必须符合指定规则- Path=/red/{segment},/blue/**Query请求参数必须包含指定参数- Query=name, Jack或者- Query=nameRemoteAddr请求者的ip必须是指定范围- RemoteAddr=192.168.1.1/24Weight权重处理 过滤器工厂GatewayFilter是网关中提供的一种过滤器,可以对进入网关的请求和微服务返回的响应做处理:Spring提供了31种不同的路由过滤器工厂。例如:名称说明AddRequestHeader给当前请求添加一个请求头RemoveRequestHeader移除请求中的一个请求头AddResponseHeader给响应结果中添加一个响应头RemoveResponseHeader从响应结果中移除有一个响应头RequestRateLimiter限制请求的流量请求头过滤器下面我们以AddRequestHeader 为例来讲解。{alert type="info"}需求:给所有进入userservice的请求添加一个请求头:Truth=itcast is freaking awesome!{/alert}只需要修改gateway服务的application.yml文件,添加路由过滤即可:spring: cloud: gateway: routes: - id: user-service uri: lb://userservice predicates: - Path=/user/** filters: # 过滤器 - AddRequestHeader=Truth, Itcast is freaking awesome! # 添加请求头当前过滤器写在userservice路由下,因此仅仅对访问userservice的请求有效。默认过滤器如果要对所有的路由都生效,则可以将过滤器工厂写到default下。格式如下:spring: cloud: gateway: routes: - id: user-service uri: lb://userservice predicates: - Path=/user/** default-filters: # 默认过滤项 - AddRequestHeader=Truth, Itcast is freaking awesome!过滤器的作用是什么?对路由的请求或响应做加工处理,比如添加请求头配置在路由下的过滤器只对当前路由的请求生效defaultFilters的作用是什么?对所有路由都生效的过滤器全局过滤器网关提供了31种,但每一种过滤器的作用都是固定的。如果我们希望拦截请求,做自己的业务逻辑则没办法实现。定义方式是实现GlobalFilter接口。自定义全局过滤器{callout color="#f0ad4e"}需求:定义全局过滤器,拦截请求,判断请求的参数是否满足下面条件:参数中是否有authorizationauthorization参数值是否为admin如果同时满足则放行,否则拦截如果同时满足则放行,否则拦截{/callout}实现:在gateway中定义一个过滤器:package com.cn.gateway.filters; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.core.annotation.Order; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; @Order(-1) @Component public class AuthorizeFilter implements GlobalFilter { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { // 1.获取请求参数 MultiValueMap<String, String> params = exchange.getRequest().getQueryParams(); // 2.获取authorization参数 String auth = params.getFirst("authorization"); // 3.校验 if ("admin".equals(auth)) { // 放行 return chain.filter(exchange); } // 4.拦截 // 4.1.禁止访问,设置状态码 exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN); // 4.2.结束处理 return exchange.getResponse().setComplete(); } } 过滤器执行顺序请求进入网关会碰到三类过滤器:当前路由的过滤器、DefaultFilter、GlobalFilter请求路由后,会将当前路由过滤器和DefaultFilter、GlobalFilter,合并到一个过滤器链(集合)中,排序后依次执行每个过滤器:排序的规则是什么呢?每一个过滤器都必须指定一个int类型的order值,order值越小,优先级越高,执行顺序越靠前。GlobalFilter通过实现Ordered接口,或者添加@Order注解来指定order值,由我们自己指定路由过滤器和defaultFilter的order由Spring指定,默认是按照声明顺序从1递增。当过滤器的order值一样时,会按照 defaultFilter > 路由过滤器 > GlobalFilter 的顺序执行。
2022年11月21日
11 阅读
0 评论
0 点赞
2022-11-03
Spring Security 的两种资源放行的策略
在Spring Security 中有两种资源放行的策略若是你但愿用户不用登陆就能访问,那么通常来讲,有两种配置策略:java第一种就是在 configure(WebSecurity web) 方法中配置放行,像下面这样:web@Override public void configure(WebSecurity web) throws Exception { web.ignoring().antMatchers("/css/**", "/js/**", "/index.html", "/img/**", "/fonts/**", "/favicon.ico", "/verifyCode"); }第二种方式是在 configure(HttpSecurity http) 方法中进行配置:springhttp.authorizeRequests() .antMatchers("/hello").permitAll() .anyRequest().authenticated()两种方式最大的区别在于,第一种方式是不走 Spring Security 过滤器链,而第二种方式走 Spring Security 过滤器链,在过滤器链中,给请求放行。有的资源可使用第一种方式额外放行,不须要验证,例如前端页面的静态资源,就能够按照第一种方式配置放行。有的资源放行,则必须使用第二种方式,例如登陆接口。你们知道,登陆接口也是必需要暴露出来的,不须要登陆就能访问到的,可是咱们却不能将登陆接口用第一种方式暴露出来,登陆请求必需要走 Spring Security 过滤器链,由于在这个过程当中,还有其余事情要作。
2022年11月03日
40 阅读
0 评论
0 点赞
2022-09-12
string常用方法
一、string常用方法valueOf(基础数据类型 b) 将基础类型数据的文本转换为字符串 substring(int beginIndex) 切割原字符串,返回一个新的字符串, beginIndex:表示从下标为几的地方开始切割 replace(char oldChar, char newChar) 返回一个新的字符串,它是通过用 newChar 替换此字符串中出现的所有 oldChar 得到的。 trim() 返回字符串的副本,忽略前导空白和尾部空白。 isEmpty() 当且仅当 length() 为 0 时返回 true。 toLowerCase() 将此 String 中的所有字符都转换为小写。 toUpperCase() 将此 String 中的所有字符都转换为大写。 二、在字符串中查询指定子字符串的位置charAt(int index) 获取指定索引处的 char 值。没有则为null indexOf(string) 返回指定字符在此字符串中第一次出现处的索引。没有则为0 lastIndexOf(int ch) 返回指定字符在此字符串中最后一次出现处的索引。 lastIndexOf(int ch, int fromIndex) 返回指定字符在此字符串中最后一次出现处的索引,从指定的索引处开始进行反向搜索。 contains(CharSequence s) 判断字符串是否包含指定的 char 值,有则返回 true。三、比较两个字符串的内容equals(Object anObject) 将此字符串与指定的对象比较。 equalsIgnoreCase(String anotherString) 将此 String 与另一个 String 比较,不考虑大小写。四、判断是否以指定的字符开头或者结尾endsWith(String suffix) 判断此字符串是否以指定的后缀结束。 startsWith(String prefix) 判断此字符串是否以指定的前缀开始。五、将字符串转换为字符数组,和字节数组format(Locale l, String format, Object... args) 格式字符串和参数返回一个格式化字符串。 getBytes(String charset) 将string转换为byte 数组。 getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin) 将string转换为字符数组 toCharArray() 将此字符串转换为一个新的字符数组。六、正则表达式matches(String regex) 判断此字符串是否匹配给定的正则表达式。 replaceAll(String regex, String replacement) 使用给定的 replacement 替换此字符串所有匹配给定的正则表达式的子字符串。 replaceFirst(String regex, String replacement) 使用给定的 replacement 替换此字符串匹配给定的正则表达式的第一个子字符串。 split(String regex) 根据给定正则表达式的匹配拆分此字符串。七、StringBuffer/StringBuilder类常用方法StringBuffer 上的主要操作是 append 和 insert 方法, append 方法始终将这些字符添加到缓冲区的末端;而 insert 方法则在指定的索引下添加字符。 StringBuffer(String str) 构造一个字符串缓冲区,并将其内容初始化为指定的字符串内容。 append(基础类型数据 b) 将 基础类型的字符串表示形式追加到序列后面。 charAt(int index) 返回此序列中指定索引处的 char 值。 delete(int start, int end) 移除此序列的子字符串中的字符。 deleteCharAt(int index) 移除此序列指定位置的 char。 insert(int offset, 基础类型数据 b) 将 基础类型参数的字符串表示形式插入指定位置中。 toString() 返回此序列中数据的字符串表示形式。
2022年09月12日
26 阅读
0 评论
0 点赞
2022-07-28
synchronized锁升级
synchronized的变化①. java5以前,只有Synchronized,这个是操作系统级别的重量级操作,重量级锁,假如锁的竞争比较激烈的话,性能下降②. 在Java早期版本中,synchronized属于重量级锁,效率低下,因为监视器锁(monitor)是依赖于底层的操作系统的Mutex Lock来实现的,挂起线程和恢复线程都需要转入内核态去完成,阻塞或唤醒一个Java线程需要操作系统切换CPU状态来完成,这种状态切换需要耗费处理器时间,如果同步代码块中内容过于简单,这种切换的时间可能比用户代码执行的时间还长”,时间成本相对较高,这也是为什么早期的synchronized效率低的原因。Java 6之后,为了减少获得锁和释放锁所带来的性能消耗,引入了轻量级锁和偏向锁③. 为什么每一个对象都可以成为一个锁?Java对象是天生的Monitor,每一个Java对象都有成为Monitor的潜质,因为在Java的设计中 ,每一个Java对象自打娘胎里出来就带了一把看不见的锁,它叫做内部锁或者Monitor锁。Monitor的本质是依赖于底层操作系统的Mutex Lock实现,操作系统实现线程之间的切换需要从用户态到内核态的转换,成本非常高④. Mutex LockMonitor是在jvm底层实现的,底层代码是c++。本质是依赖于底层操作系统的Mutex Lock实现,操作系统实现线程之间的切换需要从用户态到内核态的转换,状态转换需要耗费很多的处理器时间成本非常高。所以synchronized是Java语言中的一个重量级操作。⑤. Java 6之后,为了减少获得锁和释放锁所带来的性能消耗,引入了轻量级锁和偏向锁,需要有个逐步升级的过程,别一开始就捅到重量级锁⑥. synchronized锁:由对象头中的Mark Word根据锁标志位的不同而被复用及锁升级策略无锁偏向锁单个线程多次访问定义:①. 主要作用:当一段同步代码一直被同一个线程多次访问,由于只有一个线程那么该线程在后续访问时便会自动获得锁(偏向锁)同一个老顾客来访,直接老规矩行方便偏向锁为了解决只有在一个线程执行同步时提高性能②. 64位标记图再看(通过CAS方式修改markword中的线程ID)③. 偏向锁的理论在实际应用运行过程中发现,“锁总是同一个线程持有,很少发生竞争”,也就是说锁总是被第一个占用他的线程拥有,这个线程就是锁的偏向线程那么只需要在锁第一次被拥有的时候,记录下偏向线程ID。这样偏向线程就一直持有着锁(后续这个线程进入和退出这段加了同步锁的代码块时,不需要再次加锁和释放锁。而是直接比较对象头里面是否存储了指向当前线程的偏向锁)。如果相等表示偏向锁是偏向于当前线程的,就不需要再尝试获得锁了,直到竞争发生才释放锁。以后每次同步,检查锁的偏向线程ID与当前线程ID是否一致,如果一致直接进入同步。无需每次加锁解锁都去CAS更新对象头。如果自始至终使用锁的线程只有一个,很明显偏向锁几乎没有额外开销,性能极高。假如不一致意味着发生了竞争,锁已经不是总是偏向于同一个线程了,这时候可能需要升级变为轻量级锁,才能保证线程间公平竞争锁。偏向锁只有遇到其他线程尝试竞争偏向锁时,持有偏向锁的线程才会释放锁,线程是不会主动释放偏向锁的④. 技术实现一个synchronized方法被一个线程抢到了锁时,那这个方法所在的对象就会在其所在的Mark Word中将偏向锁修改状态位,同时还会有占用前54位来存储线程指针作为标识。若该线程再次访问同一个synchronized方法时,该线程只需去对象头的Mark Word 中去判断一下是否有偏向锁指向本身的ID,无需再进入Monitor去竞争对象了。⑤. 对于如上的③、④进行细化锁对比偏向锁的操作不用直接捅到操作系统,不涉及用户到内核转换,不必要直接升级为最高级,我们以一个account对象的“对象头”为例,假如有一个线程执行到synchronized代码块的时候,JVMM使用CAS操作把线程指针ID记录到Mark Word当中,并修改标偏向标示,标示当前线程就获得该锁。锁对象变成偏向锁(通过CAS修改对象头里的锁标志位〉,字面意思是“偏向于第一个获得它的线程”的锁。执行完同步代码块后,线程并不会主动释放偏向锁。这时线程获得了锁,可以执行同步代码块。当该线程第二次到达同步代码块时会判断此时持有锁的线程是否还是自己(持有锁的线程ID也在对象头里),JVM通过account对象的Mark Word判断:当前线程ID还在,说明还持有着这个对象的锁,就可以继续进入临界区工作。由于之前没有释放锁,这里也就不需要重新加锁。如果自始至终使用锁的线程风有一个,很明显偏向锁几乎没有额外开销,性能极高。结论:JVM不用和操作系统协商设置Mutex(争取内核),它只需要记录下线程ID就标示自己获得了当前锁,不用操作系统接入。上述就是偏向锁:在没有其他线程竞争的时候,一直偏向偏心当前线程,当前线程可以一直执行。实际上偏向锁在JDK1.6之后是默认开启的,但是启动时间有延迟, 4秒所以需要添加参数-XX:BiasedLockingStartupDelay=0,让其在程序启动时立刻启动。开启偏向锁:-XX:+UseBiasedLocking -XX:BiasedLockingStartupDelay=0关闭偏向锁:关闭之后程序默认会直接进入轻量级锁状态。-XX:-UseBiasedLockingpublic class MyObject{ public static void main(String[] args){ Object o = new Object(); new Thread(() -> { synchronized (o){ System.out.println(ClassLayout.parseInstance(o).toPrintable()); } },"t1").start(); } } //查看状态此时情况下偏向锁4秒后开启偏向锁的撤销偏向锁的撤销(偏向锁使用一种等到竞争出现才释放锁的机制,只有当其他线程竞争锁时,持有偏向锁的原来线程才会被撤销。撤销需要等待全局安全点(该时间点上没有字节码正在执行),同时检查持有偏向锁的线程是否还在执行)第一个线程正在执行synchronized方法(处于同步块),它还没有执行完,其它线程来抢夺,该偏向锁会被取消掉并出现锁升级此时轻量级锁由原持有偏向锁的线程持有,继续执行其同步代码,而正在竞争的线程会进入自旋等待获得该轻量级锁第一个线程执行完成synchronized方法(退出同步块),则将对象头设置成无锁状态并撤销偏向锁 ,重新偏向(我的理解是,其实如果线程A执行完毕,如果不再去竞争,那么就会重新线程B为偏向锁;如果线程A继续竞争,那么就会CAS自旋 也就升级到了轻量级锁)轻量级锁多线程竞争,但是任意时刻最多只有一个线程竞争,即不存在锁竞争太过激烈的情况,也就没有线程阻塞。有线程来参与锁的竞争,但是获取锁的冲突时间极短(本质就是自旋锁)轻量级锁的获取如果关闭偏向锁,就可以直接进入轻量级锁 -XX:-UseBiasedLocking自旋达到一定次数和程度没有获取则会升级锁java6之前(了解):默认启用,默认情况下自旋的次数是10次,-XX:PreBlockSpin=10来修改或者自旋线程数超过cpu核数一半Java6之后:自适应(自适应意味着自旋的次数不是固定不变的),而是根据:同一个锁上一次自旋的时间和拥有锁线程的状态来决定。重锁①. 有大量的线程参与锁的竞争,冲突性很高②. 锁标志位锁升级后,hashcode值无锁地址在31位偏向锁没有,需要获取的时候需要锁升级。当一个对象已经计算过identity hash code 它就无法进入到偏向锁状态时跳过偏向锁,直接生成轻量级锁。偏向锁过程中遇到一致性哈希计算请求,立马撤销偏向模式,膨胀为重量级锁锁的优缺点synchronized锁升级过程总结:一句话,就是先自旋,不行再阻塞。 实际上是把之前的悲观锁(重量级锁)变成在一定条件下使用偏向锁以及使用轻量级(自旋锁CAS)的形式synchronized在修饰方法和代码块在字节码上实现方式有很大差异,但是内部实现还是基于对象头的MarkWord来实现的JDK1.6之前synchronized使用的是重量级锁,JDK1.6之后进行了优化,拥有了无锁->偏向锁->轻量级锁->重量级锁的升级过程,而不是无论什么情况都使用重量级锁。. 偏向锁、轻量级锁、重量级锁总结偏向锁:适用于单线程适用的情况,在不存在锁竞争的时候进入同步方法/代码块则使用偏向锁。轻量级锁:适用于竞争较不激烈的情况(这和乐观锁的使用范围类似), 存在竞争时升级为轻量级锁,轻量级锁采用的是自旋锁,如果同步方法/代码块执行时间很短的话,采用轻量级锁虽然会占用cpu资源但是相对比使用重量级锁还是更高效。重量级锁:适用于竞争激烈的情况,如果同步方法/代码块执行时间很长,那么使用轻量级锁自旋带来的性能消耗就比使用重量级锁更严重,这时候就需要升级为重量级锁锁消除/ 锁粗化锁消除:从JIT角度看相当于无视它,synchronized (o)不存在了,这个锁对象并没有被共用扩散到其它线程使用,极端的说就是根本没有加这个锁对象的底层机器码,消除了锁的使用** * 锁消除 * 从JIT角度看相当于无视它,synchronized (o)不存在了,这个锁对象并没有被共用扩散到其它线程使用, * 极端的说就是根本没有加这个锁对象的底层机器码,消除了锁的使用 */ public class LockClearUPDemo{ static Object objectLock = new Object();//正常的 public void m1(){ //锁消除,JIT会无视它,synchronized(对象锁)不存在了。不正常的 Object o = new Object(); synchronized (o){ System.out.println("-----hello LockClearUPDemo"+"\t"+o.hashCode()+"\t"+objectLock.hashCode()); } } public static void main(String[] args){ LockClearUPDemo demo = new LockClearUPDemo(); for (int i = 1; i <=10; i++) { new Thread(() -> { demo.m1(); },String.valueOf(i)).start(); } } } /** * 锁粗化 * 假如方法中首尾相接,前后相邻的都是同一个锁对象,那JIT编译器就会把这几个synchronized块合并成一个大块, * 加粗加大范围,一次申请锁使用即可,避免次次的申请和释放锁,提升了性能 */ public class LockBigDemo { static Object objectLock = new Object(); public static void main(String[] args) { new Thread(() -> { synchronized (objectLock) { System.out.println("11111"); } synchronized (objectLock) { System.out.println("22222"); } synchronized (objectLock) { System.out.println("33333"); } },"a").start(); new Thread(() -> { synchronized (objectLock) { System.out.println("44444"); } synchronized (objectLock) { System.out.println("55555"); } synchronized (objectLock) { System.out.println("66666"); } },"b").start(); } }
2022年07月28日
37 阅读
0 评论
0 点赞
1
2
...
4