zoukankan      html  css  js  c++  java
  • 笔记:多线程访问ConcurrentHashMap对key加锁

    转载: https://www.cnblogs.com/qick/p/12494461.html

     

    近期由于工作需要,要改写以前的一个小项目,项目是C/S架构,server端部署在tomcat容器中。client端通过api请求访问server端,因此会有并发的要求。

    在server端,部署的时候我将初始化几个对象,我将他们保存在map容器中,serverIp作为key,client端并发请求的时候则从这个map中以serverIp为key取出对应的对象来进行下一步操作。这样一来,只要是请求的同一个serverIp,请求就会阻塞并先后执行,不同serverIp则会并发执行。

    但是,放在map中的对象可能会由于某些原因失效,或不能用了,这样的话就需要重新初始化这个对象,但是如果第一个请求进来时检测对象需要初始化的时候同时有第二个请求进来的话,两个请求都会去初始化这个对象,并会导致两个请求拿到了不同的对象,会有问题。针对这个情况就需要加锁,有两个办法:

    一:可以在获取map里面对应key的对象的方法上加锁,但这样的话就会阻塞掉不同key的并发请求。

    二:对map中key对应的对象再次封装,将每个serverIp作为key放入一个单独的map中,再将所有map放入到一个全局唯一的map容器中,并发请求时,针对每一个独立存放key的map加锁。

    为此,我写了个demo来验证第二个方案,特此记录下来:

    demo类:(用来模拟业务逻辑)

    复制代码
     1 public class daoDemo {
     2     private static Map<String,Map> map = new ConcurrentHashMap<>();
     3 
     4     public daoDemo(){
     5         getMap("one");
     6         getMap("two");
     7     }
     8 
     9     public static void getMap(String key){
    10         Map<String,JSch> jSchMap = new ConcurrentHashMap<>();
    11         jSchMap.put(key,new JSch());
    12         map.put(key,jSchMap);
    13     }
    14 
    15     public static void getInstance(jschBean t1, String key) throws InterruptedException{
    16         Map<String,JSch> demo;
    17         synchronized (demo = map.get(key)){
    18             System.out.println(t1.getName()+" 拿到了demo对象: "+demo.hashCode());
    19             Thread.sleep(500);
    20             System.out.println(t1.getName()+"更新前:"+map.get(key).hashCode());
    21             demo.put(key,new JSch());
    22             map.put(key, demo);
    23             System.out.println(t1.getName()+"更新后:"+map.get(key).hashCode());
    24             System.out.println(t1.getName()+" 释放了demo对象: "+demo.hashCode());
    25         }
    26 
    27     }
    28 }
    复制代码

    线程实例类:(用来模拟并发请求)

    复制代码
     1 public class jschBean extends Thread{
     2 
     3     String key;
     4     int time;
     5 
     6     public jschBean(String name, String key, int time){
     7         this.setName(name);
     8         this.key = key;
     9         this.time = time;
    10     }
    11     @Override
    12     public void run() {
    13         for(int i=0;i<5;i++){
    14             try{
    15                 daoDemo.getInstance(this, this.key);
    16                 Thread.sleep(time);
    17             }catch (Exception e){
    18                 e.printStackTrace();
    19                 System.out.println(this.getName()+" : got exception...");
    20             }
    21         }
    22     }
    23 }
    复制代码

    程序入口:

    复制代码
     1 public class syncDemo {
     2 
     3     public static void main(String[] args) {
     4         new daoDemo();
     5         jschBean jschBean1 = new jschBean("Thread-1","one",500);
     6         jschBean jschBean2 = new jschBean("Thread-2","one",1500);
     7         jschBean jschBean3 = new jschBean("Thread-3","two",500);
     8         jschBean jschBean4 = new jschBean("Thread-4","two",500);
     9         jschBean1.start();
    10         jschBean3.start();
    11         jschBean2.start();
    12         jschBean4.start();
    13     }
    14 }
    复制代码

    其中,jschBean1和jschBean2为一组,jschBean3和jschBean4为另一组,它们将会模拟两个相同的请求去访问同一个对象。 

     实验结果:

     

     实验结果:

    Thread-1 拿到了demo对象: 17092794
    Thread-3 拿到了demo对象: 924818233
    Thread-1 更新前:17092794
    Thread-3 更新前:924818233
    Thread-1 更新后:490245531
    Thread-3 更新后:1699709137
    Thread-1 释放了demo对象: 490245531
    Thread-3 释放了demo对象: 1699709137
    Thread-2 拿到了demo对象: 490245531
    Thread-4 拿到了demo对象: 1699709137
    Thread-2 更新前:490245531
    Thread-4 更新前:1699709137
    Thread-2 更新后:775304961
    Thread-2 释放了demo对象: 775304961
    Thread-1 拿到了demo对象: 775304961
    Thread-4 更新后:2000928397
    Thread-4 释放了demo对象: 2000928397
    Thread-3 拿到了demo对象: 2000928397
    Thread-1 更新前:775304961
    Thread-1 更新后:1119255817
    Thread-1 释放了demo对象: 1119255817
    Thread-3 更新前:2000928397
    Thread-3 更新后:672489720
    Thread-3 释放了demo对象: 672489720
    Thread-4 拿到了demo对象: 672489720
    Thread-4 更新前:672489720
    Thread-1 拿到了demo对象: 1119255817
    Thread-4 更新后:2038713877
    Thread-4 释放了demo对象: 2038713877
    Thread-3 拿到了demo对象: 2038713877
    Thread-1 更新前:1119255817
    Thread-1 更新后:1950831806
    Thread-1 释放了demo对象: 1950831806
    Thread-2 拿到了demo对象: 1950831806
    Thread-3 更新前:2038713877
    Thread-3 更新后:1994159918
    Thread-3 释放了demo对象: 1994159918
    Thread-4 拿到了demo对象: 1994159918
    Thread-2 更新前:1950831806
    Thread-2 更新后:552717495
    Thread-2 释放了demo对象: 552717495
    Thread-1 拿到了demo对象: 552717495
    Thread-4 更新前:1994159918
    Thread-4 更新后:2109462013
    Thread-4 释放了demo对象: 2109462013
    Thread-3 拿到了demo对象: 2109462013
    Thread-1 更新前:552717495
    Thread-1 更新后:1685769729
    Thread-1 释放了demo对象: 1685769729
    Thread-3 更新前:2109462013
    Thread-3 更新后:78130730
    Thread-3 释放了demo对象: 78130730
    Thread-4 拿到了demo对象: 78130730
    Thread-1 拿到了demo对象: 1685769729
    Thread-4 更新前:78130730
    Thread-4 更新后:951665710
    Thread-4 释放了demo对象: 951665710
    Thread-3 拿到了demo对象: 951665710
    Thread-1 更新前:1685769729
    Thread-1 更新后:814231480
    Thread-1 释放了demo对象: 814231480
    Thread-2 拿到了demo对象: 814231480
    Thread-3 更新前:951665710
    Thread-3 更新后:325443208
    Thread-3 释放了demo对象: 325443208
    Thread-4 拿到了demo对象: 325443208
    Thread-2 更新前:814231480
    Thread-2 更新后:617503857
    Thread-2 释放了demo对象: 617503857
    Thread-4 更新前:325443208
    Thread-4 更新后:1551467404
    Thread-4 释放了demo对象: 1551467404
    Thread-2 拿到了demo对象: 617503857
    Thread-2 更新前:617503857
    Thread-2 更新后:1640810124
    Thread-2 释放了demo对象: 1640810124
    Thread-2 拿到了demo对象: 1640810124
    Thread-2 更新前:1640810124
    Thread-2 更新后:1940031347
    Thread-2 释放了demo对象: 1940031347

    从结果来看,线程1和线程2是相互阻塞的,并且他们拿到的总是map中保存的key对应对象的最新值。

  • 相关阅读:
    java图形化Swing教程(一)
    NYOJ467 中缀式变后缀式 【栈】
    火云开发课堂
    Egret项目Typescript的编译报错
    Java学习笔记(八):集合类
    Java学习笔记(七):内部类、静态类和泛型
    认识JavaScript的原型
    Java学习笔记(六):面向对象、接口和抽象类
    Java学习笔记(五):异常处理
    Java学习笔记(四):流程控制
  • 原文地址:https://www.cnblogs.com/redBack/p/13821427.html
Copyright © 2011-2022 走看看