构建高性能服务(二)减小锁粒度 提高Java并发吞吐实例

2023-12-05 03:18

本文主要是介绍构建高性能服务(二)减小锁粒度 提高Java并发吞吐实例,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

提高系统并发吞吐能力是构建高性能服务的重点和难点。通常review代码时看到synchronized是我都会想一想,这个地方可不可以优化。使用synchronized使得并发的线程变成顺序执行,对系统并发吞吐能力有极大影响,我的博文 http://maoyidao.iteye.com/blog/1149015 介绍了可以从理论上估算系统并发处理能力的方法。

 

那么对于必须使用synchronized的业务场景,这里提供几个小技巧,帮助大家减小锁粒度,提高系统并发能力。

 

初级技巧 - 乐观锁

乐观锁适合这样的场景:读不会冲突,写会冲突。同时读的频率远大于写。

 

以下面的代码为例,悲观锁的实现:

Java代码 复制代码  收藏代码
  1. public Object get(Object key) {   
  2.    synchronized(map) {   
  3.       if(map.get(key) == null) {   
  4.          // set some values   
  5.       }   
  6.   
  7.        return map.get(key);   
  8.    }   
  9. }  
public Object get(Object key) {
synchronized(map) {
if(map.get(key) == null) {
// set some values
}
return map.get(key);
}
}
 

 乐观锁的实现:

Java代码 复制代码  收藏代码
  1. public Object get(Object key) {   
  2.    Object val = null;   
  3.    if((val = map.get(key) == null) {   
  4.        // 当map取值为null时再加锁判断   
  5.        synchronized(map) {   
  6.            if(val = map.get(key) == null) {   
  7.                // set some value to map...   
  8.            }   
  9.         }   
  10.    }   
  11.   
  12.     return map.get(key);   
  13. }  
public Object get(Object key) {
Object val = null;
if((val = map.get(key) == null) {
// 当map取值为null时再加锁判断
synchronized(map) {
if(val = map.get(key) == null) {
// set some value to map...
}
}
}
return map.get(key);
}

 

中级技巧 - String.intern()

乐观锁不能很好解决大量写冲突问题,但是如果很多场景下,锁实际上不是针对某个用户或者某个订单。比如一个用户必须先创建session,才能进行后面的操作。但是由于网络原因,创建用户session的请求和后续请求几乎同时达到,而并行线程可能会先处理后续请求。一般情况,需要对用户sessionMap加锁,比如上面的乐观锁。在这种场景下,使用String.inter()是一种更高效的办法。类 String 维护一个字符串池。 当调用 intern 方法时,如果池已经包含一个等于此 String 对象的字符串(该对象由 equals(Object) 方法确定),则返回池中的字符串。可见,当String相同时,String.intern()总是返回同一个对象,因此就实现了对同一用户加锁。由于锁的粒度局限于具体用户,使系统获得了最大程度的并发。

 

Java代码 复制代码  收藏代码
  1. public void doSomeThing(String uid) {   
  2.    synchronized(uid.intern()) {   
  3.        // ...   
  4.    }   
  5. }  
public void doSomeThing(String uid) {
synchronized(uid.intern()) {
// ...
}
}

 高级技巧 - 类ConcurrentHashMap

String.inter()的缺陷是类 String 维护一个字符串池是放在JVM perm区的,如果用户数特别多,导致放入字符串池的String不可控,有可能导致OOM错误或者过多的Full GC。怎么样能控制锁的个数,同时减小粒度锁呢?Java ConcurrentHashMap提供了一种很好的借鉴方式,将需要加锁的对象分为多个bucket,每个bucket加一个锁,伪代码如下:

Java代码 复制代码  收藏代码
  1. Map locks = new Map();   
  2. List lockKeys = new List();   
  3. for(int number : 1 - 10000) {   
  4.    Object lockKey = new Object();   
  5.    lockKeys.add(lockKey);   
  6.     locks.put(lockKey, new Object());   
  7. }   
  8.   
  9. public void doSomeThing(String uid) {   
  10.    Object lockKey = lockKeys.get(uid.hash() % lockKeys.size());   
  11.    Object lock = locks.get(lockKey);   
  12.       
  13.    synchronized(lock) {   
  14.       // do something   
  15.    }   
  16. }  

这篇关于构建高性能服务(二)减小锁粒度 提高Java并发吞吐实例的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/455950

相关文章

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

Spring Security--Architecture Overview

1 核心组件 这一节主要介绍一些在Spring Security中常见且核心的Java类,它们之间的依赖,构建起了整个框架。想要理解整个架构,最起码得对这些类眼熟。 1.1 SecurityContextHolder SecurityContextHolder用于存储安全上下文(security context)的信息。当前操作的用户是谁,该用户是否已经被认证,他拥有哪些角色权限…这些都被保

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

Java架构师知识体认识

源码分析 常用设计模式 Proxy代理模式Factory工厂模式Singleton单例模式Delegate委派模式Strategy策略模式Prototype原型模式Template模板模式 Spring5 beans 接口实例化代理Bean操作 Context Ioc容器设计原理及高级特性Aop设计原理Factorybean与Beanfactory Transaction 声明式事物

Java进阶13讲__第12讲_1/2

多线程、线程池 1.  线程概念 1.1  什么是线程 1.2  线程的好处 2.   创建线程的三种方式 注意事项 2.1  继承Thread类 2.1.1 认识  2.1.2  编码实现  package cn.hdc.oop10.Thread;import org.slf4j.Logger;import org.slf4j.LoggerFactory

嵌入式QT开发:构建高效智能的嵌入式系统

摘要: 本文深入探讨了嵌入式 QT 相关的各个方面。从 QT 框架的基础架构和核心概念出发,详细阐述了其在嵌入式环境中的优势与特点。文中分析了嵌入式 QT 的开发环境搭建过程,包括交叉编译工具链的配置等关键步骤。进一步探讨了嵌入式 QT 的界面设计与开发,涵盖了从基本控件的使用到复杂界面布局的构建。同时也深入研究了信号与槽机制在嵌入式系统中的应用,以及嵌入式 QT 与硬件设备的交互,包括输入输出设

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟 开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚 第一站:海量资源,应有尽有 走进“智听