Reputation: 388
I am getting a Null pointer exception in my Hashmap which is a global variable and is getting updated by separate threads. While debugging all threads are running fine and updating the Hashmap but when i execute program one thread throws Null pointer.
public class RunEngine {
/**
* @param args
*/
public static Map<Integer, List<Event>> queue_map = new HashMap<Integer, List<Event>>();
public static void main(String[] args) {
/*
* check file present in data set folder or not , if present fetch the file name
* and store then in a list
*/
File folder = new File(ConfigurationParameters.FOLDER_PATH);
File[] listOfFiles = folder.listFiles();
/* Create a thread pool for number of Publishers which you want to initialise */
ThreadPoolExecutor executor = new ThreadPoolExecutor(ConfigurationParameters.P_NUMBER,
ConfigurationParameters.P_NUMBER + 3, 100, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(), new ThreadPoolExecutor.CallerRunsPolicy()); // P_NUMBER = 2
for (int i = 1; i <= ConfigurationParameters.P_NUMBER; i++) {
ConnectP conn = new ConnectP(
ConfigurationParameters.FOLDER_PATH + "\\" + listOfFiles[i - 1].getName(),
ConfigurationParameters.DISTRIBUTION_RANDOM, i);
executor.execute(conn);
}
executor.shutdown();
}
}
The ConnectP class looks like:
public class ConnectP implements Runnable {
private String file_path;
private String distribution_constant;
private int pub_id;
/**
* @param file_path
* @param distribution_constant
*/
public ConnectP(String file_path, String distribution_constant, int pub_id) {
super();
this.file_path = file_path;
this.distribution_constant = distribution_constant;
this.pub_id = pub_id;
}
public void streamevent(List<Event> eventlist, String distributionconstant)
throws InterruptedException {
if (distributionconstant.matches(ConfigurationParameters.PUBLISHER_DISTRIBUTION_RANDOM)) {
List<Event> publisherqueue = new ArrayList<>();
RunEngine.queue_map.put(pub_id, publisherqueue);
for (Event event : eventlist) {
long start = System.currentTimeMillis(); // get present system timestamp
event.setTimeStamp(start);
publisherqueue.add(event); // add to publisher queue
Random rand = new Random();
int value = rand.nextInt(1000); // add a random seed for streaming
Thread.sleep(value); // sleep the process for that value
System.out.println("Publisher " + String.valueOf(pub_id) + " : " + RunEngine.queue_map.get(pub_id).size()); **(throwing exception line 68)**
}
}
}
// function to connect to source file and return list of publication event
public List<Event> connectsource(String filepath) {
// return list after reading file
return list;
}
@Override
public void run() {
// TODO Auto-generated method stub
List<Event> event = this.connectsource(file_path); // connect to source
try {
System.out.println("THREAD " + String.valueOf(pub_id)+ " Initiated");
this.streamevent(event, distribution_constant);**(throwing exception line 121)**
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
The exception I am getting is
Exception in thread "pool-1-thread-1" java.lang.NullPointerException
at org.test.event.ConnectP.streamevent(ConnectP.java:68)
at org.test.event.ConnectP.run(ConnectP.java:121)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
I will be thankful for help. If there is some efficient way to do same, will be highly appreciated.
Upvotes: 1
Views: 986
Reputation: 116938
I am getting a Null pointer exception in my Hashmap which is a global variable and is getting updated by separate threads.
HashMap
is not a synchronized class. If multiple threads are updating the map at the same time then it is very possible that their memory view of this map will get out of sync which could cause NPEs, infinite loops, or other bad things.
<tldr> The easiest way to do this is to use the ConcurrentHashMap
class which takes care of synchronization for you. </tldr>
// thread-1
RunEngine.queue_map.put(pub_id, publisherqueue);
...
// thread-2
RunEngine.queue_map.get(pub_id).size()
Right. One thread looks to be putting and another is getting. When you do this in multiple threads then you need to worry about:
Basically each thread has a local memory cache per-processor that allows it to access cached results efficiently without having to get everything from main memory. So when thread-1 updates the map, it may only do so in it's cache. If thread-2 then gets from the map it might see none of of the updates or, worse, a partial update of the map depending on the virtual memory details. If both threads are updating the map then the one that flushes its memory cache to main memory will overwrite the updates made by the other one.
This is true with any object that you are sharing between threads. Only immutable objects with final fields can be shared between threads without worry. Otherwise you need to use the volatile
or synchronized
keywords to ensure they are shared appropriately. To do this correctly is pretty difficult and requires a lot of experience with Java threads and memory synchronization constructs.
The Java tutorial about synchronization may be a good place to get started.
Upvotes: 1