当前位置:  编程技术>java/j2ee

使用JAVA实现高并发无锁数据库操作步骤分享

    来源: 互联网  发布时间:2014-10-29

    本文导语:  1. 并发中如何无锁。一个很简单的思路,把并发转化成为单线程。Java的Disruptor就是一个很好的例子。如果用java的concurrentCollection类去做,原理就是启动一个线程,跑一个Queue,并发的时候,任务压入Queue,线程轮训读取这个Queue...

1. 并发中如何无锁。
一个很简单的思路,把并发转化成为单线程。Java的Disruptor就是一个很好的例子。如果用java的concurrentCollection类去做,原理就是启动一个线程,跑一个Queue,并发的时候,任务压入Queue,线程轮训读取这个Queue,然后一个个顺序执行。
在这个设计模式下,任何并发都会变成了单线程操作,而且速度非常快。现在的node.js, 或者比较普通的ARPG服务端都是这个设计,“大循环”架构。
这样,我们原来的系统就有了2个环境:并发环境 + ”大循环“环境
并发环境就是我们传统的有锁环境,性能低下。
"大循环"环境是我们使用Disruptor开辟出来的单线程无锁环境,性能强大。

2. ”大循环“环境 中如何提升处理性能。
一旦并发转成单线程,那么其中一个线程一旦出现性能问题,必然整个处理都会放慢。所以在单线程中的任何操作绝对不能涉及到IO处理。那数据库操作怎么办?
增加缓存。这个思路很简单,直接从内存读取,必然会快。至于写、更新操作,采用类似的思路,把操作提交给一个Queue,然后单独跑一个Thread去一个个获取插库。这样保证了“大循环”中不涉及到IO操作。

问题再次出现:
如果我们的游戏只有个大循环还容易解决,因为里面提供了完美的同步无锁。
但是实际上的游戏环境是并发和“大循环”并存的,即上文的2种环境。那么无论我们怎么设计,必然会发现在缓存这块上要出现锁。

3. 并发与“大循环”如何共处,消除锁?
我们知道如果在“大循环”中要避免锁操作,那么就用“异步”,把操作交给线程处理。结合这2个特点,我稍微改下数据库架构。
原本的缓存层,必然会存在着锁,例如:

代码如下:

public TableCache
{
  private HashMap caches = new ConcurrentHashMap();
}

这个结构是必然的了,保证了在并发的环境下能够准确的操作缓存。但是”大循环“却不能直接操作这个缓存进行修改,所以必须启动一个线程去更新缓存,例如:

代码如下:

private static final ExecutorService EXECUTOR = Executors.newSingleThreadExecutor();
EXECUTOR.execute(new LatencyProcessor(logs));

class LatencyProcessor implements Runnable
{
  public void run()
  { 
    // 这里可以任意的去修改内存数据。采用了异步。
  }
}

OK,看起来很漂亮。但是又有个问题出现了。在高速存取的过程中,非常有可能缓存还没有被更新,就被其他请求再次获取,得到了旧的数据。

4. 如何保证并发环境下缓存数据的唯一正确?
我们知道,如果只有读操作,没有写操作,那么这个行为是不需要加锁的。
我使用这个技巧,在缓存的上层,再加一层缓存,成为”一级缓存“,原来的就自然成为”二级缓存“。有点像CPU了对不?
一级缓存只能被”大循环“修改,但是可以被并发、”大循环“同时获取,所以是不需要锁的。
当发生数据库变动,分2种情况:
1)并发环境下的数据库变动,我们是允许有锁的存在,所以直接操作二级缓存,没有问题。
2)”大循环“环境下数据库变动,首先我们把变动数据存储在一级缓存,然后交给异步修正二级缓存,修正后删除一级缓存。
这样,无论在哪个环境下读取数据,首先判断一级缓存,没有再判断二级缓存。
这个架构就保证了内存数据的绝对准确。
而且重要的是:我们有了一个高效的无锁空间,去实现我们任意的业务逻辑。

最后,还有一些小技巧提升性能。
1. 既然我们的数据库操作已经被异步处理,那么某个时间,需要插库的数据可能很多,通过对表、主键、操作类型的排序,我们可以删除一些无效操作。例如:
a)同一个表同一个主键的多次UPdate,取最后一次。
b)同一个表同一个主键,只要出现Delete,前面所有操作无效。
2. 既然我们要对操作排序,必然会存在一个根据时间排序,如何保证无锁呢?使用
private final static AtomicLong _seq = new AtomicLong(0);
即可保证无锁又全局唯一自增,作为时间序列。


    
 
 

您可能感兴趣的文章:

  • 懂nginx,帮下忙,使用nginx实现大并发
  • 趋势的一道面试题:网络编程中设计并发服务器,使用多进程 与 多线程 ,请问有什么区别?
  • java线程并发countdownlatch类使用示例
  • java线程并发cyclicbarrier类使用示例
  • python高并发异步服务器核心库forkcore使用方法
  • java线程并发blockingqueue类使用示例
  • java多线程并发中使用Lockers类将多线程共享资源锁定
  • Django项目使用示例步骤及代码
  • 使用xenocode代码混淆加密的操作步骤
  • linux下不使用sudo命令执行docker的操作步骤
  • 使用X manager连接oracle数据库的步骤
  • 使用libpcap实现抓包程序的步骤及代码示例
  • 想搞嵌入式驱动的开发,请大虾给个简单例程(通过SPI读写外扩存储芯片),以及开发步骤及应注意的地方,怎么加入内核和使用该驱动?谢谢
  • 使用mongovue把sqlserver数据导入mongodb的步骤
  • 安装linux red hat 7.3 方法步骤及一些使用基础
  • linux 下怎么检查电脑上是否安装或使用了某软件 具体方法及步骤?
  • BCP 大容量数据导入导出工具使用步骤
  • sqlserver游标使用步骤示例(创建游标 关闭游标)
  • 使用python搭建Django应用程序步骤及版本冲突问题解决
  • [200分]在原来一块硬盘上已经安装rh linux9的电脑上,如何加一块新买的硬盘,新硬盘也在linux系统使用!最好给个详细的步骤
  • Python爬虫框架Scrapy安装使用步骤
  • 使用scrapy实现爬网站例子和实现网络爬虫(蜘蛛)的步骤
  • android开发教程之ubuntu使用adb连接小米2的步骤和adb调试方法
  • CentOS 5.5使用yum安装LAMP(php环境)步骤分享
  • Jquery使用Firefox FireBug插件调试Ajax步骤讲解
  • 使用ViewPager实现android软件使用向导功能实现步骤
  • python socket网络编程步骤详解(socket套接字使用)
  • linux使用gcc编译c语言共享库步骤
  •  
    本站(WWW.)旨在分享和传播互联网科技相关的资讯和技术,将尽最大努力为读者提供更好的信息聚合和浏览方式。
    本站(WWW.)站内文章除注明原创外,均为转载、整理或搜集自网络。欢迎任何形式的转载,转载请注明出处。












  • 相关文章推荐
  • 在Python3中使用urllib实现http的get和post提交数据操作
  • [请置顶]关于Linux的安装使用问题 请放到 软件使用/操作系统 里提问
  • TinyXML(c++下操作xml的库)介绍,下载地址及使用代码举例
  • 请教,如何使用JDOM操作XML文档?
  • c++ stl multimap基本操作使用技巧详细介绍
  • 紧急:请问有谁会使用Free BSD操作系统,请给予指点
  • 求ibm6000的中文使用手册 !从来没用过服务器,现在急需使用它,不知如何使用! 急!!!!! iis7站长之家
  • linux下使用tcl操作excel
  • windows7操作系统介绍及各种使用技巧总结
  • 说说你使用的操作系统
  • 急问:!!如何使用shell作如下操作?
  • 操作系统的使用的处理死锁的算法
  • 有谁知道linux操作系统察看cpu使用率的命令,回答正确给高分,急,在线等待!!!
  • 有谁告诉我如何使用main中的args进行输入输出的操作?
  • 有没有使用最新内核的占用空间较小的linux操作系统
  • 只使用InputStream/OutputStream进行IO操作行吗?
  • 在用户态如何使用原子操作?
  • jquery链式操作的正确使用方法
  • 如何用ANSI C来获取操作系统文件系统使用率?
  • 在unix上如何使用磁带机,相关命令有那些,操作系统版本为aix 4.3
  • 使用cmd命令行窗口操作SqlServer的方法
  • C++ I/O 成员 tellg():使用输入流读取流指针
  • 在测试memset函数的执行效率时,分为使用Cash和不使用Cash辆种方式,该如何控制是否使用缓存?
  • C++ I/O 成员 tellp():使用输出流读取流指针
  • 求ibm6000的中文使用手册 !从来没用过服务器,现在急需使用它,不知如何使用! 急!!!!!
  • Python不使用print而直接输出二进制字符串
  • 请问:在使用oracle数据库作开发时,是使用pro*c作开发好些,还是使用库函数如oci等好一些啊?或者它们有什么区别或者优缺点啊?
  • Office 2010 Module模式下使用VBA Addressof
  • 急求结果!!假设一个有两个元素的信号量集S,表示了一个磁带驱动器系统,其中进程1使用磁带机A,进程2同时使用磁带机A和B,进程3使用磁带机B。
  • windows下tinyxml.dll下载安装使用(c++解析XML库)
  • c#中SAPI使用总结——SpVoice的使用方法


  • 站内导航:


    特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

    ©2012-2021,,E-mail:www_#163.com(请将#改为@)

    浙ICP备11055608号-3