`

构建高性能服务(二)java高并发锁的3种实现

 
阅读更多

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

 

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

 

初级技巧 - 乐观锁

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

 

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

 

public Object get(Object key) {
   synchronized(map) {
      if(map.get(key) == null) {
         // set some values
      }

       return map.get(key);
   }
}
 

 乐观锁的实现:

 

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加锁,比如上面的乐观锁。在这种场景下,可以讲锁限定到用户本身上,即从原来的

 

lock.lock();

    int num=storage.get(key);

    storage.set(key,num+1);

lock.unlock();

更改为:

lock.lock(key);

    int num=storage.get(key);

    storage.set(key,num+1);

lock.unlock(key);

这个比较类似于数据库表锁和行锁的概念,显然行锁的并发能力比表锁高很多。

 

使用String.inter()是这种思路的一种具体实现。类 String 维护一个字符串池。 当调用 intern 方法时,如果池已经包含一个等于此 String 对象的字符串(该对象由 equals(Object) 方法确定),则返回池中的字符串。可见,当String相同时,String.intern()总是返回同一个对象,因此就实现了对同一用户加锁。由于锁的粒度局限于具体用户,使系统获得了最大程度的并发。

 

public void doSomeThing(String uid) {
   synchronized(uid.intern()) {
       // ...
   }
}

 

CopyOnWriteMap?

既然说到了“类似于数据库中的行锁的概念”,就不得不提一下MVCC,Java中CopyOnWrite类实现了MVCC。Copy On Write是这样一种机制。当我们读取共享数据的时候,直接读取,不需要同步。当我们修改数据的时候,我们就把当前数据Copy一份副本,然后在这个副本 上进行修改,完成之后,再用修改后的副本,替换掉原来的数据。这种方法就叫做Copy On Write。

但是,,,JDK并没有提供CopyOnWriteMap,为什么?下面有个很好的回答,那就是已经有了ConcurrentHashMap,为什么还需要CopyOnWriteMap?

Fredrik Bromee 写道
I guess this depends on your use case, but why would you need a CopyOnWriteMap when you already have a ConcurrentHashMap?

For a plain lookup table with many readers and only one or few updates it is a good fit.

Compared to a copy on write collection:

Read concurrency:

Equal to a copy on write collection. Several readers can retrieve elements from the map concurrently in a lock-free fashion.

Write concurrency:

Better concurrency than the copy on write collections that basically serialize updates (one update at a time). Using a concurrent hash map you have a good chance of doing several updates concurrently. If your hash keys are evenly distributed.

If you do want to have the effect of a copy on write map, you can always initialize a ConcurrentHashMap with a concurrency level of 1.
 

高级技巧 - 类ConcurrentHashMap

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

 

Map locks = new Map();
List lockKeys = new List();
for(int number : 1 - 10000) {
   Object lockKey = new Object();
   lockKeys.add(lockKey);
	locks.put(lockKey, new Object());
}

public void doSomeThing(String uid) {
   Object lockKey = lockKeys.get(uid.hash() % lockKeys.size());
   Object lock = locks.get(lockKey);
   
   synchronized(lock) {
      // do something
   }
}
 

 

关于高性能缓存的设计,请参考构建高性能服务系列之一:http://maoyidao.iteye.com/blog/1559420

 

分享到:
评论
4 楼 ppgf135 2013-08-29  
lock.lock(key)

有这种写法吗
3 楼 teasp 2013-06-09  
第一个所谓的乐观锁是错误的。CopyOnWrite只是在读多写少的情况下划算。
2 楼 miroku 2012-07-04  
第一种好像是有问题,双重检查锁在指令重排序时会有问题。
1 楼 maoyidao 2012-06-24  
还有一种思路,如果读远远大于写,写全部用一个单线程完成。使用volatile关键字。volatile只提供可见性,即线程能发现最新的修改值,但不能保证原子性。因此需要使用单线程写,但多并发的读线程可以立刻看到最新的修改。

相关推荐

    JAVA高性能高并发服务器架构pdf文档视频资源

    在IT行业中,Java是一种广泛应用的编程语言,尤其在构建高性能、高并发的服务器架构方面具有显著优势。本资源集合包含了关于“JAVA高性能高并发服务器架构”的PDF文档和视频,旨在帮助开发者深入理解如何利用Java...

    构建高性能的大型分布式java应用

    在构建高性能的大型分布式Java应用时,我们面临的是复杂的技术挑战和优化目标。要实现这样的系统,我们需要深入了解Java平台的特点,以及如何利用其优势来处理大规模数据和高并发请求。以下是一些关键的知识点: 1....

    实战Java高并发程序设计(高清版)

    Java作为一种多平台、高性能的编程语言,是实现高并发程序的理想选择。 书中的内容可能涵盖了以下几个核心知识点: 1. **线程基础**:线程是操作系统分配CPU时间的基本单位,是实现并发的基础。书中可能会详细介绍...

    实现Java高并发隔离 模拟

    在Java编程中,高并发是系统设计中的一...总之,实现Java高并发隔离是提升系统性能和稳定性的重要手段,它涵盖了多种并发控制策略和技术。通过深入理解和实践这些概念,开发者可以设计出更高效、更健壮的并发应用程序。

    Java高性能文件上传及下载

    在Java开发中,实现高性能的文件上传和下载是至关重要的技术环节,特别是在处理大量用户交互或者大数据量传输的场景下。本资料集主要探讨如何利用Java技术和相关工具库来优化这一过程,确保系统的稳定性和效率。 ...

    java面试题_高并发、高可用、分布式(9题)

    在Java面试中,高并发、高可用和分布式是考察开发者技术深度和广度的...通过深入理解并掌握以上知识点,开发者能够更好地应对Java面试中关于高并发、高可用和分布式的问题,也能在实际项目中构建出高效、稳定的系统。

    利用Java开发高性能、高并发Web应用

    在Java开发领域,构建高性能、高并发的Web应用是一项核心任务。这涉及到多个技术层面的综合运用,包括但不限于系统架构设计、线程管理、数据访问优化、缓存策略、负载均衡以及性能监控等。以下是一些关键的知识点,...

    Java秒杀系统方案优化 高性能高并发实战

    ### Java秒杀系统方案优化与高性能高并发实战 在当今互联网快速发展的背景下,高并发、高性能成为了考验系统架构的关键指标之一。特别是在电商领域中的“秒杀”活动,它不仅能够吸引大量用户参与,还能有效提升商品...

    Java_Socket开发高并发小型服务器

    Java Socket 开发高并发小型服务器涉及的核心概念是网络编程中的Socket技术,以及如何利用Java语言构建能够处理大量并发连接的服务端。首先,Socket是网络通信中的一个基础概念,它为两台计算机之间的通信提供了接口...

    构建高性能服务(一)ConcurrentSkipListMap和链表构建高性能Java Memcached

    而在构建高性能Java Memcached时,链表(如`LinkedList`)和并发队列(如`LinkedBlockingQueue`)可以作为优化缓存管理和淘汰策略的工具,以适应高并发和大容量数据的挑战。结合合适的数据结构和算法,我们可以构建...

    实战Java高并发程序设计-试读

    《实战Java高并发程序设计》是一本专注于Java并发编程实践的书籍,试读版提供了前两章的内容,为读者提供了一个初步了解并发编程基础的窗口。在Java领域,并发编程是构建高性能、高效率系统的关键技术,对于软件开发...

    基于JDK源码解析Java领域中的并发锁之设计与实现.pdf

    在Java并发编程中,理解和掌握并发锁的原理与实现至关重要,因为它们是解决多线程环境下的互斥和同步问题的关键。本文将基于JDK源码解析Java领域中的并发锁,探讨AQS基础同步器、LockSupport、Condition接口、Lock...

    java高并发秒杀api源码

    这个"java高并发秒杀api源码"很可能是一个实现这类功能的示例项目,它结合了Spring和MyBatis两大主流框架,以提升系统性能和可维护性。下面,我们将深入探讨这些关键知识点。 首先,`Spring`是一个全面的企业级应用...

    高并发高性能服务器

    在IT领域,构建高并发高性能服务器是至关重要的技术挑战,特别是在大数据时代,处理大量用户请求、实时数据交换以及保持高效的服务响应成为系统设计的核心。本资料包提供的"高并发高性能服务器"源码提供了深入理解这...

    JAVA版基于netty的物联网高并发智能网关.zip

    "JAVA版基于netty的物联网高并发智能网关"项目正致力于解决这一问题,通过利用Java语言和Netty框架构建一个高性能、可扩展的网络通信系统。Netty是一个异步事件驱动的网络应用框架,适用于开发高效的服务器和客户端...

    java_如何利用Java开发高性能、高并发Web应用

    在Java世界中,开发高性能、高并发的Web应用程序是一项关键任务,这关乎到系统的稳定性、扩展性和用户体验。本文将深入探讨如何借助Java技术栈来实现这一目标。 首先,选择合适的框架至关重要。Spring Boot是一个...

    java抽奖系统后台 springboot+mybatis redis队列处理高并发.zip

    在本项目中,"java抽奖系统后台 springboot+mybatis redis队列处理高并发.zip",我们可以探索几个关键的IT技术及其在构建高效抽奖系统中的应用。以下是对这些技术的详细说明: 1. **SpringBoot**: SpringBoot是...

    基于Java应用的高并发高可用集群服务器的设计与实现_王瑛.pdf

    【基于Java应用的高并发高可用集群服务器设计与实现】 在当今互联网高度发达的时代,构建一个稳定、高效、可扩展的服务器集群对于任何单位或企业来说都是至关重要的。本文主要探讨了如何利用Java应用程序构建一个高...

Global site tag (gtag.js) - Google Analytics