2017-09-19 120 views
1

在类CACallHandler有一个由我创建的方法,即checkCallAllowed。我已将所有内容都用作ConcurrentHashMap和AtomicInteger。Java:我的方法线程安全吗?

请忽略checkCallAllowed的逻辑,但我想知道如果多个线程将同时访问同一个对象上的此方法,那么它会安全。

我不想synchronize整个方法,因为会有一个表演。

请求您的帮助。

我已经执行此方法与30个线程有和没有方法同步,都给出相同的结果。所以想要了解是否会有200个线程,那么它会安全或不安全。

public class CACallHandler { 

public ThrottleCallAlert throttleCallAlert ; 

Map<String, TCACriteria> criteriaMap = new HashMap<String, TCACriteria>(); 

List<TCAListener> listenerList = new LinkedList< TCAListener>(); 
Map<String, AtomicInteger[]> intervalMap = new ConcurrentHashMap<String, AtomicInteger[]>(); 
Map<String, AtomicInteger> oddMap = new ConcurrentHashMap<String, AtomicInteger>(); 
Map<String, AtomicInteger> evenMap = new ConcurrentHashMap<String, AtomicInteger>(); 
Map<String, List<ThrottleAlarmType> > alarmsRaised = new ConcurrentHashMap<String, List<ThrottleAlarmType>>(); 


public Map<String, AtomicInteger> getCurrentMap(){ 

    String abc = new SimpleDateFormat("ss").format(new Date()); 
    if(Integer.parseInt(abc) % 2 == 0){ 
     // even map 
     return evenMap; 
    }else{ 
     // odd map 
     return oddMap; 
    } 
} 

public String getCriteria(String callingNo, String Origin1, String Origin2){ 

    String criteriaName = ""; 
    for (Map.Entry<String, TCACriteria> entry : criteriaMap.entrySet()) 
    { 
     TCACriteria criteria = entry.getValue(); 
     if(callingNo.equals(criteria.callingNo) || Origin1.equals(criteria.sipOrigin) || Origin2.equals(criteria.inapOrigin)){ 
      criteriaName = entry.getKey(); 
      return criteriaName; 
     } 
    } 
    return criteriaName; 
} 

public boolean checkCallAllowed(String calling, String Origin1, String Origin2){ 

    boolean returnFlag = false; 

    String currentCriteria = getCriteria(calling, Origin1, Origin2); // test 

    if(!currentCriteria.isEmpty()){ 

     String abc = new SimpleDateFormat("ss").format(new Date()); 
     if(Integer.parseInt(abc) % 2 == 0){ 
      //taking odd map based on seconds 
      if(oddMap.get(currentCriteria).get() != 0){ 

       for(int i=0; i < intervalMap.get(currentCriteria).length; i++){ 
        System.out.println("aaaaa :"+ intervalMap.get(currentCriteria)[i].get()); 
        if(intervalMap.get(currentCriteria)[i].get() == -1){ 
         if(oddMap.get(currentCriteria).get() >= throttleCallAlert.getLwm()){ 
          intervalMap.get(currentCriteria)[i].set(oddMap.get(currentCriteria).get()); 

         }else{ 
          if(alarmsRaised.get(currentCriteria) != null && oddMap.get(currentCriteria).get() < throttleCallAlert.getLwm()){ 

           if(alarmsRaised.get(currentCriteria).contains(ThrottleAlarmType.MAJOR)){ 
            System.out.println("ALARM [email protected]@!!---MAJOR-->>>. currentCriteria "+currentCriteria); 
            listenerList.get(0).alarmCleared(currentCriteria, ThrottleAlarmType.MAJOR); 
            alarmsRaised.put(currentCriteria, alarmsRaised.get(currentCriteria)).set(2, ThrottleAlarmType.NONE); 
           } 
          } 

          for(int j=0; j < intervalMap.get(currentCriteria).length; j++){ 

           intervalMap.get(currentCriteria)[j] = new AtomicInteger(-1); 
          } 
         } 
         break; 
        } 

        if(i == intervalMap.get(currentCriteria).length - 1){ 
         int majorAlarm = 0; 
         boolean raiseAlarmRequired = true; 
         System.out.println("array not -1 111"); 
         for(int j=0; j < intervalMap.get(currentCriteria).length; j++){ 
          if(intervalMap.get(currentCriteria)[j].get() < throttleCallAlert.getLwm()){ 
           raiseAlarmRequired = false; 
          } 
          intervalMap.get(currentCriteria)[j] = new AtomicInteger(-1); 
         } 

         if(raiseAlarmRequired){ 
          System.out.println("ALARM RAISED--11---->>>. currentCriteria " + currentCriteria); 

          //start 
          if(majorAlarm == intervalMap.get(currentCriteria).length){ // major 
           if((alarmsRaised.get(currentCriteria) != null && ! alarmsRaised.get(currentCriteria).contains(ThrottleAlarmType.MAJOR))){ 
            returnFlag = false; 
            alarmsRaised.put(currentCriteria, alarmsRaised.get(currentCriteria)).set(2, ThrottleAlarmType.MAJOR); 
            listenerList.get(0).alarmRaised(currentCriteria, ThrottleAlarmType.MAJOR); 

           } 
          } 
          //end 
         } 

         if(alarmsRaised.get(currentCriteria) != null && oddMap.get(currentCriteria).get() < throttleCallAlert.getLwm()){ 
          if(alarmsRaised.get(currentCriteria).contains(ThrottleAlarmType.WARNING)){ 
           System.out.println("ALARM cleared-111----->>>. currentCriteria "+currentCriteria); 
           listenerList.get(0).alarmCleared(currentCriteria, ThrottleAlarmType.WARNING); 
           alarmsRaised.put(currentCriteria, alarmsRaised.get(currentCriteria)).set(0, ThrottleAlarmType.NONE); 
          } 

         } 
         intervalMap.get(currentCriteria)[0].set(oddMap.get(currentCriteria).get()); 
        } 

       } 
       oddMap.get(currentCriteria).set(0); 
      } 

      // even map 
      evenMap.get(currentCriteria).incrementAndGet(); 

     }else{ 
      // takeing even map same as odd map mentioned above 
      } 
    } 

    return returnFlag; 
} 

}

+0

那些地图的内容会在程序执行过程中发生变化吗?如果他们这样做,我认为你可能会在方法中产生不一致的读取,因为你的条件逻辑在读取之间没有同步。 –

+0

好吧,看起来这个方法本身至少在变异警报图。它看起来没有线程安全。我的意思是,来自CHM的数据访问是线程安全的,但这些调用之间的逻辑没有同步。 –

+0

@米克助记符:方法本身就是改变报警图,奇图,偶图,区间图的值。这些是并发哈希映射,值是原子整数。它不是线程安全的吗?如果不是,我该怎么做才能保证线程安全 – VJS

回答

0

不,你的方法不是线程安全的,但你的地图是。 事实上,它的方法不同步使得它是异步的,但访问地图是线程安全的,也就是说,一次只能有一个线程访问。

我分析了你的代码,但我承认我无法理解她的业务逻辑。为了提高性能并使线程更加安全,我将处理分为两个方法并使它们同步。我还对代码进行了一些更改,我对其原因进行了评论。 我最大的困难是了解谈判部分(哪些值可以在竞争中处理或不能竞争)以及可能受到什么影响,但我相信你也可以尝试使用synchronized块,例如在currentCriteriaValue变量中synchronized( currentCriteriaValue){... 有什么可以改进的是,我相信要变得更好,我必须有谈判规则的领域。

public class CACallHandler { 

    //Only one SimpleDateFormat instance is enought to format all dates 
    private SimpleDateFormat sdfSS = new SimpleDateFormat("ss"); 

    public ThrottleCallAlert throttleCallAlert; 

    List<TCAListener> listenerList = new LinkedList< TCAListener>(); 
    Map<String, TCACriteria> criteriaMap = new HashMap<String, TCACriteria>(); 
    Map<String, AtomicInteger[]> intervalMap = new ConcurrentHashMap<String, AtomicInteger[]>(); 
    Map<String, AtomicInteger> oddMap = new ConcurrentHashMap<String, AtomicInteger>(); 
    Map<String, AtomicInteger> evenMap = new ConcurrentHashMap<String, AtomicInteger>(); 
    Map<String, List<ThrottleAlarmType> > alarmsRaised = new ConcurrentHashMap<String, List<ThrottleAlarmType>>(); 
    static String[] testeValues = {"callingNo", "sipOrigin", "inapOrigin", "A", "B", "C"}; 


    {//Populates values to test 

     throttleCallAlert = new ThrottleCallAlert(); 

     criteriaMap.put("callingNo", new TCACriteria()); 
     criteriaMap.put("sipOrigin", new TCACriteria()); 
     criteriaMap.put("inapOrigin", new TCACriteria()); 

     evenMap.put("callingNo", new AtomicInteger(1)); 
     evenMap.put("sipOrigin", new AtomicInteger(2)); 
     evenMap.put("inapOrigin", new AtomicInteger(3)); 

     oddMap.put("callingNo", new AtomicInteger(1)); 
     oddMap.put("sipOrigin", new AtomicInteger(2)); 
     oddMap.put("inapOrigin", new AtomicInteger(3)); 

     intervalMap.put("callingNo", new AtomicInteger[] { new AtomicInteger(1), new AtomicInteger(2), new AtomicInteger(3) }); 
     intervalMap.put("sipOrigin", new AtomicInteger[] { new AtomicInteger(1), new AtomicInteger(2), new AtomicInteger(3) }); 
     intervalMap.put("inapOrigin", new AtomicInteger[] { new AtomicInteger(1), new AtomicInteger(2), new AtomicInteger(3) }); 
    } 


    public static void main(String[] args) throws InterruptedException { 
     CACallHandler handler = new CACallHandler(); 
     int threads = 10000; 
     ExecutorService taskExecutor = Executors.newFixedThreadPool(threads); 
     //Thread.sleep(12000); 
     Date startTime = new Date(); 
     for(int i = 0 ; i < threads; i++) { 
      int i1 = ThreadLocalRandom.current().nextInt(0, 5 + 1); 
      int i2 = ThreadLocalRandom.current().nextInt(0, 5 + 1); 
      int i3 = ThreadLocalRandom.current().nextInt(0, 5 + 1); 
      taskExecutor.execute(new Thread(){ public void run() {handler.checkCallAllowed(testeValues[i1], testeValues[i2], testeValues[i3]);} } ); 
     } 
     taskExecutor.shutdown(); 
     taskExecutor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS); 
     Date finishTime = new Date(); 
     System.out.println("Execution time in ms: " + (finishTime.getTime() - startTime.getTime())); 

    } 



    /** 
    * Return the odd or even map based on current time 
    * @return Map 
    */ 
    public Map<String, AtomicInteger> getCurrentMap(){ 
     switch(getCurrentMapType()) { 
      case EVEN: return evenMap; 
      case ODD: return oddMap; 
      default: return null; 
     } 
    } 

    /** 
    * Check if criteriaMap has the [callingNo | Origin1 | Origin2] passed 
    * @param callingNo - 
    * @param Origin1 
    * @param Origin2 
    * @return String - the criteriaMap key equals to parameter or empty string 
    */ 
    public String getCriteria(String callingNo, String Origin1, String Origin2){ 
     for (Map.Entry<String, TCACriteria> entry : criteriaMap.entrySet()){ 
      TCACriteria criteria = entry.getValue(); 
      if(callingNo.equals(criteria.callingNo) || Origin1.equals(criteria.sipOrigin) || Origin2.equals(criteria.inapOrigin)) 
       return entry.getKey(); 
     } 
     return null; 
    } 

    /** 
    * get odd map type based on seconds 
    * @return MapType 
    */ 
    private MapType getCurrentMapType() { 
     return MapType.EVEN;//No odd implementation 
     /*if(Integer.parseInt(sdfSS.format(new Date())) % 2 == 0){ 
      return MapType.EVEN; 
     }else{ 
      return MapType.ODD; 
     }*/  
    } 

    /** 
    * Get the currente criteria based on parameters then process it 
    * @param calling 
    * @param Origin1 
    * @param Origin2 
    * @return 
    */ 
    public boolean checkCallAllowed(String calling, String Origin1, String Origin2){ 
     String currentCriteria = getCriteria(calling, Origin1, Origin2); 
     if(currentCriteria != null){ 
      switch(getCurrentMapType()) { 
       case EVEN: return proccessEvenMapType(currentCriteria); 
       case ODD: return proccessOddMapType(currentCriteria); 
       default: return false; //TODO check it 
      } 
     } 
     return false; 
    } 

    /** 
    * Process currentcriteria based on even Map 
    * @param currentCriteria 
    * @return boolean - always false?? 
    */ 
    private synchronized boolean proccessEvenMapType(String currentCriteria) { 
     boolean returnFlag = false; //TODO this variable never receivs true..?? 
     //Only one call to map, reduce the time on searching and processing 
     Integer currentCriteriaValue = oddMap.get(currentCriteria).get(); 
      if(currentCriteriaValue != 0){ 
       //Only one call to map, reduce the time on searching and processing 
       AtomicInteger[] intervalArray = intervalMap.get(currentCriteria); 
       for(int intervalIndex=0; intervalIndex < intervalArray.length; intervalIndex++){ 
        AtomicInteger currentInterval = intervalArray[intervalIndex]; 
        System.out.println("aaaaa :"+ currentInterval.get()); 
        if(currentInterval.get() == -1){ 
         if(currentCriteriaValue >= throttleCallAlert.getLwm()){ 
          currentInterval.set(currentCriteriaValue); 
         }else{ 
          List<ThrottleAlarmType> alarmTypeList = alarmsRaised.get(currentCriteria) ; 
          if(alarmTypeList != null && currentCriteriaValue < throttleCallAlert.getLwm()){ 
           if(alarmTypeList.contains(ThrottleAlarmType.MAJOR)){ 
            System.out.println("ALARM [email protected]@!!---MAJOR-->>>. currentCriteria "+currentCriteria); 
            listenerList.get(0).alarmCleared(currentCriteria, ThrottleAlarmType.MAJOR); 
            alarmsRaised.put(currentCriteria, alarmTypeList).set(2, ThrottleAlarmType.NONE); 
           } 
          } 
          for(int j=0; j < intervalArray.length; j++){ 
           intervalArray[j] = new AtomicInteger(-1); 
          } 
         } 
         break; 
        } 

        if(intervalIndex == intervalArray.length - 1){ 
         int majorAlarm = 0; 
         boolean raiseAlarmRequired = true; 
         System.out.println("array not -1 111"); 
         for(int j=0; j < intervalArray.length; j++){ 
          if(intervalArray[j].get() < throttleCallAlert.getLwm()){ 
           raiseAlarmRequired = false; 
          } 
          intervalArray[j] = new AtomicInteger(-1); 
         } 

         if(raiseAlarmRequired){ 
          System.out.println("ALARM RAISED--11---->>>. currentCriteria " + currentCriteria); 
          //start 
          if(majorAlarm == intervalArray.length){ // major 
           if((alarmsRaised.get(currentCriteria) != null && ! alarmsRaised.get(currentCriteria).contains(ThrottleAlarmType.MAJOR))){ 
            returnFlag = false; 
            alarmsRaised.put(currentCriteria, alarmsRaised.get(currentCriteria)).set(2, ThrottleAlarmType.MAJOR); 
            listenerList.get(0).alarmRaised(currentCriteria, ThrottleAlarmType.MAJOR); 
           } 
          } 
          //end 
         } 

         if(alarmsRaised.get(currentCriteria) != null && currentCriteriaValue < throttleCallAlert.getLwm()){ 
          if(alarmsRaised.get(currentCriteria).contains(ThrottleAlarmType.WARNING)){ 
           System.out.println("ALARM cleared-111----->>>. currentCriteria "+currentCriteria); 
           listenerList.get(0).alarmCleared(currentCriteria, ThrottleAlarmType.WARNING); 
           alarmsRaised.put(currentCriteria, alarmsRaised.get(currentCriteria)).set(0, ThrottleAlarmType.NONE); 
          } 
         } 
         intervalArray[0].set(currentCriteriaValue); 
        } 

       } 
       oddMap.get(currentCriteria).set(0); 
      } 
     // even map 
     evenMap.get(currentCriteria).incrementAndGet(); 
     return returnFlag; 
    } 

    private boolean proccessOddMapType(String currentCriteria) { 
     System.out.println("proccessOddMapType Not implemented yet!!"); 
     return false; 
    } 

} 

enum MapType{ 
    ODD, EVEN; 
} 
+0

好的。我如何使线程安全并以最低的性能命中 – VJS

+0

您能发送可执行代码,以便我可以提出更改建议吗? – thiago

+0

我怎么送你?你的邮件ID? – VJS