Java:我的方法线程安全吗?

时间:2017-09-19 18:55:03

标签: java multithreading

在班级CACallHandler中,我创建了一种方法,即checkCallAllowed。我把所有内容都当作ConcurrentHashMap和AtomicInteger。

请忽略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 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;
}

}

1 个答案:

答案 0 :(得分:0)

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

我分析了你的代码,但我承认我无法理解她的业务逻辑。为了提高性能并使其对线程更安全,我将处理分为两种方法并使它们同步。我还对代码进行了一些更改,我对其原因进行了评论。 我最大的困难是理解谈判部分(可以在竞争中处理哪些值)以及可以在其中受到影响的内容,但我相信您也可以尝试使用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 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;
}