并发中如何无锁。一个很简单的思路把并发转化成为单线程。Java的Disruptor就是一个很好的例子。如果用java的concurrentCollection类去做原理就是启动一个线程跑一个Queue并发的时候任务压入Queue线程轮训读取这个Queue然后一个个顺序执行。在这个设计模式下任何并发都会变成了单线程操作而且速度非常快。现在的node.js, 或者比较普通的ARPG服务端都是这个设计“大循环”架构。这样我们原来的系统就有了2个环境并发环境 ”大循环“环境并发环境就是我们传统的有锁环境性能低下。”大循环“环境是我们使用Disruptor开辟出来的单线程无锁环境性能强大。2. ”大循环“环境 中如何提升处理性能。一旦并发转成单线程那么其中一个线程一旦出现性能问题必然整个处理都会放慢。所以在单线程中的任何操作绝对不能涉及到IO处理。那数据库操作怎么办增加缓存。这个思路很简单直接从内存读取必然会快。至于写、更新操作采用类似的思路把操作提交给一个Queue然后单独跑一个Thread去一个个获取插库。这样保证了“大循环”中不涉及到IO操作。问题再次出现如果我们的游戏只有个大循环还容易解决因为里面提供了完美的同步无锁。但是实际上的游戏环境是并发和“大循环”并存的即上文的2种环境。那么无论我们怎么设计必然会发现在缓存这块上要出现锁。3. 并发与“大循环”如何共处消除锁我们知道如果在“大循环”中要避免锁操作那么就用“异步”把操作交给线程处理。结合这2个特点我稍微改下数据库架构。原本的缓存层必然会存在着锁例如public TableCache{private HashMapString, Object caches new ConcurrentHashMapString, Object();}这个结构是必然的了保证了在并发的环境下能够准确的操作缓存。但是”大循环“却不能直接操作这个缓存进行修改所以必须启动一个线程去更新缓存例如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);