0

I use a map to store data by running several sqls. Recently I wanna improve the efficiency of searching, so I create some threads, each thread corresponds to each sql, then put query results into the map at the same time. When running the code, I get NullPointerExceptions but do not know why. Here is my code:

public Map<String, Object> getIndexStatistics(final Integer themeId, final String time, final Integer projectId) {
    final Map<String, Object> res = new ConcurrentHashMap<>();
    final AtomicInteger ai = new AtomicInteger(0);
    new Thread(new Runnable() {
        @Override
        public void run() {
            res.put("part1", getSumVolume(themeId, time, true, projectId));
            ai.getAndIncrement();
        }
    }).start();
    new Thread(new Runnable() {
        @Override
        public void run() {
            res.put("part2", getVolumeTendency(themeId, time, projectId));
            ai.getAndIncrement();
        }
    }).start();
    new Thread(new Runnable() {
        @Override
        public void run() {
            res.put("part3", getPlatformDistribution(themeId, time, projectId));
            ai.getAndIncrement();
        }
    }).start();
    new Thread(new Runnable() {
        @Override
        public void run() {
            res.put("part4", getFeelingProportion(themeId, time, projectId));
            ai.getAndIncrement();
        }
    }).start();
    new Thread(new Runnable() {
        @Override
        public void run() {
            res.put("part5", getLocationDistribution(themeId, time, projectId));
            ai.getAndIncrement();
        }
    }).start();
    new Thread(new Runnable() {
        @Override
        public void run() {
            res.put("part6", getPositiveCloudList(themeId, time));
            ai.getAndIncrement();
        }
    }).start();
    new Thread(new Runnable() {
        @Override
        public void run() {
            res.put("part7", getNegativeCloudList(themeId, time));
            ai.getAndIncrement();
        }
    }).start();
    new Thread(new Runnable() {
        @Override
        public void run() {
            res.put("part8", getLatestNegativeSentiments(themeId, time, projectId));
            ai.getAndIncrement();
        }
    }).start();
    new Thread(new Runnable() {
        @Override
        public void run() {
            res.put("part9", getHotRank(themeId, time, null, projectId));
            ai.getAndIncrement();
        }
    }).start();
    new Thread(new Runnable() {
        @Override
        public void run() {
            res.put("statistic_counts", getCountStatistics(time, themeId, projectId));
            ai.getAndIncrement();
        }
    }).start();
    new Thread(new Runnable() {
        @Override
        public void run() {
            res.put("region_counts", getRegionDistribution(themeId, time, projectId));
            ai.getAndIncrement();
        }
    }).start();
    while (true) {
        if (ai.get() == 11) {
            break;
        }
    }
    return res;
}

stacktrace:

java.lang.NullPointerException
    at java.util.concurrent.ConcurrentHashMap.putVal(ConcurrentHashMap.java:1011)
    at java.util.concurrent.ConcurrentHashMap.put(ConcurrentHashMap.java:1006)
    at com.bolaa.main.service.impl.ProjectNameDataServiceImpl$7.run(ProjectNameDataServiceImpl.java:309)
    at java.lang.Thread.run(Thread.java:748)

By the way, all of the operations are addings and puttings. Do I need to use AtomicInteger and ConcurrentHashMap?

  • [A Minimal, Complete, and Verifiable example](https://stackoverflow.com/help/mcve), please? That is, without the calls to `getSumVolume` and other methods that we don’t have. – Ole V.V. Oct 24 '18 at 09:06
  • 2
    [shan](https://stackoverflow.com/users/3388404/shan) would like to comment: have you checked the value? maybe it was null! – Ole V.V. Oct 24 '18 at 09:07
  • `res` and `ai` seems to be initializated so probably the Exception is being launched in some of your inner methods, those that we don't have – Aldeguer Oct 24 '18 at 09:08
  • 1
    I'll check the results of the inner code. – code-life balance Oct 24 '18 at 09:10
  • 2
    From ConcurrentHashMap doc "Like Hashtable but unlike HashMap, this class does not allow null to be used as a key or value. " –  Oct 24 '18 at 09:11
  • 2
    Possibly related: [Why does ConcurrentHashMap prevent null keys and values?](https://stackoverflow.com/questions/698638/why-does-concurrenthashmap-prevent-null-keys-and-values) – Ole V.V. Oct 24 '18 at 09:12
  • Yes, you need `ConcurrentHashMap` to put from more than one thread. You probably don’t need an `AtomicInteger` since the map has a `size()` method that will tell you how many mappings are in there. – Ole V.V. Oct 24 '18 at 09:13
  • I checked my code and one of the inner methods returns null as you expected. The usage is correct but ConcurrentHashMap doesn't allow to put null values. Thanks to all of you. – code-life balance Oct 24 '18 at 09:22
  • On a side note, if you are on Java 8, you could use `new Thread(() -> { //my code for this thread }).start();` – YetAnotherBot Oct 24 '18 at 13:36

1 Answers1

3

You can use another type of Thread Pools [1] to improve the efficiency and testing result of functions.

The problem is one function doesn't return a value [2]. Like Hashtable but unlike HashMap, this class does not allow null to be used as a key or value.[2]

You can change the argument of function to value 123 in all threads, and to find the error function. or testing

final int errno= -1
if(getFeelingProportion(themeId, time, projectId)==null)
        res.put("part4", errno);
else
        res.put("part4", getFeelingProportion(themeId, time, projectId));
ai.getAndIncrement();

[1] https://docs.oracle.com/javase/tutorial/essential/concurrency/pools.html [2] https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ConcurrentHashMap.html