简体   繁体   中英

Java : Is my method thread safe?

In class CACallHandler there is a method created by me ie checkCallAllowed . I have taken everything as ConcurrentHashMap and AtomicInteger.

Please ignore the logic of checkCallAllowed but i want to know that if multiple threads will access this method on the same object concurrently, then will it safe.

i dont want to synchronize the entire method as there will be a performce hit.

Requesting your help.

i have executed this method with 30 threads with and without method synchronized, both are giving same result. So want to understand if there will be 200 threads then it will be safe or not.

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 cleared-111@@!!---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;
}

}

No, your method is not Thread Safe, but your maps are. The fact that its method is not synchronized makes it asynchronous, but access to Maps is Thread Safe, that is, only one thread can access at a time.

I analyzed your code but I confess that I could not understand her business logic. To improve your performance and make it more secure to threads, I've separated the processing into two methods and made them synchronized. I also made some changes to the code which I commented their reasons. My biggest difficulty has been to understand the negotiating part (what values can be processed in competition or not) and what can be affected in it, but I believe you can also try to use synchronized blocks, for example in the currentCriteriaValue variable synchronized (currentCriteriaValue ) {... What could improve was it, I believe that to get better I would have to have the field of negotiation rule.

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 cleared-111@@!!---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;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM