当前位置: 首页 > news >正文

高端网站定制的案例外包公司 网站建设 深圳

高端网站定制的案例,外包公司 网站建设 深圳,2015年网站设计,合肥网站建设王道下拉強转载自 Java 并发实践 — ConcurrentHashMap 与 CAS最近在做接口限流时涉及到了一个有意思问题#xff0c;牵扯出了关于concurrentHashMap的一些用法#xff0c;以及CAS的一些概念。限流算法很多#xff0c;我主要就以最简单的计数器法来做引。先抽象化一下需求#xff1a;…转载自 Java 并发实践 — ConcurrentHashMap 与 CAS最近在做接口限流时涉及到了一个有意思问题牵扯出了关于concurrentHashMap的一些用法以及CAS的一些概念。限流算法很多我主要就以最简单的计数器法来做引。先抽象化一下需求统计每个接口访问的次数。一个接口对应一个url也就是一个字符串每调用一次对其进行加一处理。可能出现的问题主要有三个 多线程访问需要选择合适的并发容器分布式下多个实例统计接口流量需要共享内存流量统计应该尽可能不损耗服务器性能 但这次的博客并不是想描述怎么去实现接口限流而是主要想描述一下遇到的问题所以第二点暂时不考虑即不使用Redis。 说到并发的字符串统计立即让人联想到的数据结构便是ConcurrentHashpMapString,Long urlCounter;如果你刚刚接触并发可能会写出如代码清单1的代码 代码清单1 12345678910111213141516171819202122232425262728293031323334353637383940414243444546publicclass CounterDemo1 {    privatefinal MapString, Long urlCounter newConcurrentHashMap();    //接口调用次数1    publiclong increase(String url) {        Long oldValue urlCounter.get(url);        Long newValue (oldValue null) ? 1L : oldValue 1;        urlCounter.put(url, newValue);        returnnewValue;    }    //获取调用次数    publicLong getCount(String url){        returnurlCounter.get(url);    }    publicstatic void main(String[] args) {        ExecutorService executor Executors.newFixedThreadPool(10);        finalCounterDemo1 counterDemo newCounterDemo1();        intcallTime 100000;        finalString url http://localhost:8080/hello;        CountDownLatch countDownLatch newCountDownLatch(callTime);        //模拟并发情况下的接口调用统计        for(inti0;icallTime;i){            executor.execute(newRunnable() {                Override                publicvoid run() {                    counterDemo.increase(url);                    countDownLatch.countDown();                }            });        }        try{            countDownLatch.await();        }catch(InterruptedException e) {            e.printStackTrace();        }        executor.shutdown();        //等待所有线程统计完成后输出调用次数        System.out.println(调用次数counterDemo.getCount(url));    }}console output调用次数96526都说concurrentHashMap是个线程安全的并发容器所以没有显示加同步实际效果呢并不如所愿。 问题就出在increase方法concurrentHashMap能保证的是每一个操作putget,delete…本身是线程安全的但是我们的increase方法对concurrentHashMap的操作是一个组合先get再put所以多个线程的操作出现了覆盖。如果对整个increase方法加锁那么又违背了我们使用并发容器的初衷因为锁的开销很大。我们有没有方法改善统计方法呢代码清单2罗列了concurrentHashMap父接口concurrentMap的一个非常有用但是又常常被忽略的方法。 代码清单2 1234567891011121314/** * Replaces the entry for a key only if currently mapped to a given value. * This is equivalent to *  pre {code * if (map.containsKey(key) Objects.equals(map.get(key), oldValue)) { *   map.put(key, newValue); *   return true; * } else *   return false; * }/pre * * except that the action is performed atomically. */booleanreplace(K key, V oldValue, V newValue);这其实就是一个最典型的CAS操作except that the action is performed atomically.这句话真是帮了大忙我们可以保证比较和设置是一个原子操作当A线程尝试在increase时旧值被修改的话就回导致replace失效而我们只需要用一个循环不断获取最新值直到成功replace一次即可完成统计。 改进后的increase方法如下 代码清单3 1234567891011121314151617181920212223publiclong increase2(String url) {        Long oldValue, newValue;        while(true) {            oldValue urlCounter.get(url);            if(oldValue null) {                newValue 1l;                //初始化成功退出循环                if(urlCounter.putIfAbsent(url, 1l) null)                    break;                //如果初始化失败说明其他线程已经初始化过了            }else{                newValue oldValue 1;                //1成功退出循环                if(urlCounter.replace(url, oldValue, newValue))                    break;                //如果1失败说明其他线程已经修改过了旧值            }        }        returnnewValue;    }console output调用次数100000再次调用后获得了正确的结果上述方案看上去比较繁琐因为第一次调用时需要进行一次初始化所以多了一个判断也用到了另一个CAS操作putIfAbsent他的源代码描述如下 代码清单4 123456789101112131415161718192021222324252627282930313233/**     * If the specified key is not already associated     * with a value, associate it with the given value.     * This is equivalent to     *  pre {code     * if (!map.containsKey(key))     *   return map.put(key, value);     * else     *   return map.get(key);     * }/pre     *     * except that the action is performed atomically.     *     * implNote This implementation intentionally re-abstracts the     * inappropriate default provided in {code Map}.     *     * param key key with which the specified value is to be associated     * param value value to be associated with the specified key     * return the previous value associated with the specified key, or     *         {code null} if there was no mapping for the key.     *         (A {code null} return can also indicate that the map     *         previously associated {code null} with the key,     *         if the implementation supports null values.)     * throws UnsupportedOperationException if the {code put} operation     *         is not supported by this map     * throws ClassCastException if the class of the specified key or value     *         prevents it from being stored in this map     * throws NullPointerException if the specified key or value is null,     *         and this map does not permit null keys or values     * throws IllegalArgumentException if some property of the specified key     *         or value prevents it from being stored in this map     */     V putIfAbsent(K key, V value);简单翻译如下“如果调用该方法时key-value 已经存在则返回那个 value 值。如果调用时 map 里没有找到 key 的 mapping返回一个 null 值”。值得注意点的一点就是concurrentHashMap的value是不能存在null值的。实际上呢上述的方案也可以把Long替换成AtomicLong可以简化实现 ConcurrentHashMap 1234567891011privateAtomicLongMapString urlCounter3 AtomicLongMap.create();publiclong increase3(String url) {    longnewValue urlCounter3.incrementAndGet(url);    returnnewValue;}publicLong getCount3(String url) {    returnurlCounter3.get(url);}看一下他的源码就会发现其实和代码清单3思路差不多只不过功能更完善了一点。 和CAS很像的操作我之前的博客中提到过数据库的乐观锁用version字段来进行并发控制其实也是一种compare and swap的思想。 杂谈网上很多对ConcurrentHashMap的介绍众所周知这是一个用分段锁实现的一个线程安全的map容器但是真正对他的使用场景有介绍的少之又少。面试中能知道这个容器的人也确实不少问出去也就回答一个分段锁就没有下文了但我觉得吧有时候一知半解反而会比不知道更可怕。 参考 [1] https://my.oschina.net/mononite/blog/144329[2] http://www.tuicool.com/articles/zuui6z
http://www.zqtcl.cn/news/179629/

相关文章:

  • 品牌网站建设 蝌蚪5小微信分销怎么做
  • 二级域名建站虚拟主机与云服务器的区别
  • 如何安装网站模板文件网站维护具体做啥
  • 怎么建设官方网站登封网络推广公司
  • 苏州画廊网站建设vs2015 建设微网站
  • 海南网站建设及维护自己创建网站403
  • 网站推广的意义怎样把建好的网站上传到互联网
  • 王店镇建设中学网站seo搜索排名优化是什么意思
  • 北京哪家网站建设公司比较好js页面下载wordpress
  • 网站开发组岗位建设银行官网网站人事
  • 找公司做网站运营怎么样百度推广代运营
  • flask做克隆网站网站放到云服务器上怎么做
  • 有网站怎样做推广精品网站源码资源程序下载
  • 怎么建设淘宝联盟的网站梧州网站设计公司
  • 注册查询官方网站网站建设pad版本是什么
  • 做网站先得注册域名吗网站cdn+自己做
  • 甘肃省建设厅网站非织梦做的网站能仿吗
  • 天元建设集团网站苏州门户网站建设
  • 建设网站需要学习什么语言福州优化搜索引擎
  • 网站开发大致多少钱手机上怎么制作网站吗
  • 重庆网站seo营销模板wordpress学习 知乎
  • 桃子网站logowordpress post meta
  • 做网站一般需要什么青岛网络推广
  • 东莞网站建设 光龙wordpress4.6 nodejs
  • 宁海县建设局网站网站建设行业前景
  • 2003网站的建设谷歌seo新手快速入门
  • 网站建设服务开发网页制作下载链接怎么做
  • 网站更改域名河源建网站
  • 陕西培训网站建设校园网站建设目的
  • 做网站赚钱容易吗怎么创建自己网站平台