Search code examples
multithreadingconcurrencyconcurrenthashmap

Concurrent writing elements into the ConcurrentHashMap admits element


Concurrent writing elements into the ConcurrentHashMap admits element. Requirements: writing must be done in different threads. Is there way to use advantages of the ConcurrentHashMap and do writing without blocking and sleeping?

Is there good code for iterator that accessed from different treads. Or is there other good variant to keep ieratian looking on the effectively-final requirement?

public class Task3v2 {

public static void main(String[] args) {
    System.out.println("ConcurrentHashMap : "+timeIt(new ConcurrentHashMap<Integer, String>()));
}

static Iterator<Integer> integerIterator;

static {createIterator();}

private static void createIterator() {
    integerIterator=
    Stream.iterate(0, i -> i + 1).limit(100).collect(Collectors.toList()).iterator();
}
public static double timer(Runnable block) {
    long start = System.nanoTime();
    try {
        block.run();
    } finally {
        long end = System.nanoTime();
        return(end - start);

    }
}

public static double timeIt(Map<Integer, String> map){
    return timer(
            ()->{
        new Thread(()->{
            fillMap(map);
            System.out.println("invoked");
            readMap(map);
        }).start();
    });
}

private static void fillMap(Map<Integer, String> map){
    int[] index = new int[1];
    String[] tmp = new String[1];
    try {
        Thread.sleep(100);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    for(int i = 0; i< 100; i++){
        index[0] = i;
        tmp[0] = "Name"+i;
        new Thread(()->{
            int a = integerIterator.next();
            System.out.println("a :"+a);
            map.put(a,"Name"+a);
        }
        ).start();
    }
}

private static void readMap(Map<Integer, String> map){
    int[] index2 = new int[1];
    for(int i = 0; i< 100; i++){
        index2[0]=i;
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(()->{
            System.out.println("map.get(index2[0]) :"+map.get(index2[0]));
        }).start();
    }
}

}

Finally the map must pass following tests:

public class Task3Test {

static ConcurrentHashMap<Integer, String> map;

@BeforeClass
public static void fillMap(){
    map = new ConcurrentHashMap<>();
    timeIt(map);
}


@Test
public void elementPresenceTest(){
    //GIVEN
    //map;

    //WHEN
    List<Integer> actualPresenceList = Stream.iterate(0, i -> i + 1).limit(100)
            .filter(n->(map.entrySet().stream().map(Map.Entry::getKey)
                    .anyMatch(m->(n.equals(m))))).collect(Collectors.toList());
    actualPresenceList.forEach(System.out::println);
    System.out.println("size"+actualPresenceList.size());

    //THEN
    List<Integer>expectedPresenceList = Stream.iterate(0, i -> i + 1).limit(100).collect(Collectors.toList());
    assertThat(actualPresenceList, Matchers.contains(expectedPresenceList));
}

@Test
public void elementAmountTest() {
    assertThat(map.entrySet(), Matchers.hasSize(100));
}

}


Solution

  • Iterator is not acceptable for concurrency. Solution is: static Queue integerQueue = Stream.iterate(0, i -> i + 1).limit(100).collect(Collectors.toCollection(LinkedBlockingQueue::new));

    There is needed to keep sleeping for the readMap() method to provide time for the writing method. If there is needed to keep any data structure on adding new elements in concurrency environment, it should be used queue instead of map.