本故事纯属虚构,如有雷同,纯属巧合!
故事背景
悟空师徒4人取经回来后,因不耐收到管教,就回到了花果山,带领一帮猴子猴孙逍遥自在的过日子,奈何因在阎王殿里将生死薄中的猴子猴孙的名字都划去了,猴子猴孙是越来越多。
悟空最是没有耐心的,无法一一管教,随向太白金星讨教。
猿类分级考试
太白金星给了主意:考试分级。
并且给出了题目:
创建一个通用的计数器,能计量很多的东西,如金箍棒。
参考答案如下:
猿类分阶:一~九等级 依次上升
一阶猿类
public class Counter1 { private static int cnt=0; public int increase() { return ++cnt; } public int decrease() { return --cnt; } }
旁白:实现了功能。
二阶猿类
public class Counter2 { private static long cnt=0; public long increase() { return ++cnt; } public long decrease() { return --cnt; } }
旁白:考虑了int的范围限制,long的范围更广泛。
三阶猿类
public class Counter3 { private static long cnt=0; public synchronized long increase() { return ++cnt; } public synchronized long decrease() { return --cnt; } }
旁白:考虑了并发环境下的执行
四阶猿类
public class Counter4 { private static AtomicLong cnt=new AtomicLong(0); public long increase() { return cnt.getAndIncrement(); } public long decrease() { return cnt.getAndDecrement(); } }
旁白:考虑了并发环境下的cas性能更优
五阶猿类
public class Counter5 { private static LongAdder cnt=new LongAdder(); public long increase() { cnt.increment(); return cnt.longValue(); } public long decrease() { cnt.decrement(); return cnt.longValue(); } }
旁白:在单线程下,并发问题没有暴露,两者没有体现出差距;随着并发量加大,LongAdder 的 increment 操作更加优秀,而 AtomicLong 的 get 操作则更加优秀。鉴于在计数器场景下的特点—写多读少,所以写性能更高的 LongAdder 更加适合。
六阶猿类
public class Counter6 { private static JdbcTemplateUtils jdbc=new JdbcTemplateUtils(); private static long cnt=0; public long increase() { cnt=jdbc.getCnt(); return jdbc.setCnt(++cnt); } public long decrease() { cnt=jdbc.getCnt(); return jdbc.setCnt(--cnt);; } }
旁白:考虑了在集群环境下保证数据的唯一性和一致性。
七阶猿类
public class Counter7 { private static RedisclusterUtils redis=new RedisclusterUtils(); private static long cnt=0; public long increase() { return redis.incr(cnt); } public long decrease() { return redis.decr(cnt);; } }
旁白:考虑了计数器集群下的并发性能问题,同样的实现可以使用zk或者mongo等内存数据库。
八阶猿类
public class Counter8 { private static JdbcTempalteUtils jdbc=new JdbcTempalteUtils(); private static RedisclusterUtils redis=new RedisclusterUtils(); private static long cnt=0; public long increase() { if(redis.exsits(cnt)) { return redis.incr(cnt); } cnt=jdbc.getCnt(key); ++cnt; redis.set(key,cnt); return cnt; } public long decrease() { if(redis.exsits(cnt)) { return redis.decr(cnt); } cnt=jdbc.getCnt(key); --cnt; redis.set(key,cnt); return cnt; } }
旁白:考虑到redis宕机或者不可用的情况下的处理,有备份方案。
九阶猿类
这个要免考的。
参考资料:
【1】https://mp.weixin.qq.com/s/yAvJFZWxfKb38IDMjQd5zg