CodeGuru Concurrency

  1. Scroll down or look up to see another comment. pr4 I thought concurrentHashMap was a thread-safe data structure, but there was one problem. ConcurrentHashMap does not lock the entire map when performing put command for performance. Of course, you can declare a function to be synchronized , but in this case, it is the same as a single-thread, which can cause performance problems.

  2. A more detailed what CodeGuru points out is as follows.

    if (map.containsKey(product_code)) { <-----second function doing...
        return map.get(product_code);
    }else{
        return map.put(product_code, new Concurrency(product_code,"test")); <-----first function doing...
    }
    
  3. The result of containsKey() cannot be guaranteed because put() of CuncurrenctHashMap does not lock the entire map. The concurrency problem is a very difficult error to occur if it is a simple code or a few thraed. However, if an error occurs, it will be very difficult to fix the problem if you do not understand the correct behavior of ConcurrentHashMap. CodeGuru can find these problems. It also provides a solution.

  4. As suggested by CodeGuru Reviewer, you can guarantee atomicity by performing the putIfAbsent() function once instead of the put() and containsKey(). We will fix the code as follows.

    -if (map.containsKey(product_code)) { 
    -    return map.get(product_code);
    -}else{
    -    return map.put(product_code, new Concurrency(product_code,"test"));
    +return map.putIfAbsent(product_code,new Concurrency(product_code,"test", date));
    
  5. The full code of singletonRepo.java is here..

    package com.example.concurrencysample;
    
    import java.text.DateFormat;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.HashMap;
    import java.util.concurrent.*;
    
    import com.amazonaws.auth.AWSCredentials;
    import com.amazonaws.auth.AWSStaticCredentialsProvider;
    import com.amazonaws.auth.BasicAWSCredentials;
    import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
    import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
    import com.amazonaws.services.dynamodbv2.document.DynamoDB;
    import com.amazonaws.services.dynamodbv2.document.Item;
    import com.amazonaws.services.dynamodbv2.document.Table;
    import com.amazonaws.services.dynamodbv2.model.AttributeDefinition;
    import com.amazonaws.services.dynamodbv2.model.CreateTableRequest;
    import com.amazonaws.services.dynamodbv2.model.KeySchemaElement;
    import com.amazonaws.services.dynamodbv2.model.KeyType;
    import com.amazonaws.services.dynamodbv2.model.ProvisionedThroughput;
    import com.amazonaws.services.dynamodbv2.model.ScalarAttributeType;
    import com.amazonaws.regions.Regions;
    
    public class SingletonRepo {
        private static String ACCESS_KEY = "";
        private static String SECERET_KEY = "";
        private ConcurrentHashMap<Integer, Concurrency> map = new ConcurrentHashMap<>();
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        private static SingletonRepo singletonrepo = null;
        static AmazonDynamoDB dynamodb;
    
        private SingletonRepo() {
        }
    
        public synchronized static SingletonRepo getInstance() {
            if (singletonrepo == null) {
                singletonrepo = new SingletonRepo();
    
    
                dynamodb = AmazonDynamoDBClientBuilder
                        .standard()
                .withRegion(Regions.US_WEST_2)
                .build();
                System.out.println("singleton repo instance created");
            }
            return singletonrepo;
        }
        public Concurrency get(int product_code){
            return map.get(product_code);
        }
    
        public Concurrency putKey(int product_code ) {           
            Date date = Util.getRandomDate();
            return map.putIfAbsent(product_code,new Concurrency(product_code,"test", date));
        }
        public void delKey(int product_code ) { 
            if (map.containsKey(product_code)) {
                map.remove(product_code);
            }
        }
        public int getMapCount() {
            return map.size();
        }
        public synchronized void clearHashMap() {
            map.clear();
            System.out.println("ClearMap!");
        }
        public Concurrency getKey(int product_number) {
            return map.get(product_number);  
        }
    }
    

    Edit the code and push.

    git add .
    git commit -m "fix put(), containsKey()-> putifAbsent()"
    git push
    
  6. the problem has been fixed, we will end the Pull-Request. Click the Merg button in the top right corner of the AWS console. pr3

  7. Since master has not changed, we choose Fast forward merge. Source is develop branch, uncheck the box of Delete source branch develop after merging?. pr3

  8. Select Pipeline pipelines from the left menu. Now you can see the build progress as the develop code goes into the master. pr3

  9. After a while, you can see that the master’s build and deployment is complete. The newly changed code is safely merge in the production environment. pr3

  10. Using the CD/CI pipeline, modifications of the code can be safely reflected as the master. Also, developers can easily see the test results and process of the code by simply using Commit and push. pr3

  11. UnitTest and CodeReview are one of the best ways to improve code quality. For each process, you can use the CodeBuild Report and CodeGuru Reviwer to make code review and UnitTest safer and more effective.

Now let’s check the profiling results that are actually deployed and running.