Updated code of NullPointerException problem with ConcurrentHashMap

久未见 提交于 2020-08-10 20:12:10

问题


I am trying to do a multi thread simulator where there are workers (threads) and jobs to solve, so every thread has to solve a job and start to solve the next in order, the integer of the job is the time in seconds that is required to solve the job, this is a simulation so the code prints the index of the thread with the initialization time of the job but it hasn't to be sleeping that number of seconds.

The problem is that i'm getting a NullPointerException only when there are a lot of jobs with the same number like 4 12 (4 threads for 12 jobs) 1 1 1 1 1 1 1 1 1 1 1 1 (12 jobs that require 1 second to be completed) it launches the exception in this part:

if (workersReady.size()>1) { 
              bestWorker = workersReady.iterator().next();
              workersReady.remove(bestWorker);
              workersReadyAtTimeT.remove(currentTime);
              workersReadyAtTimeT.put(currentTime,workersReady);
              nextTimesQueue.add(currentTime);

The input has to be like this:

First line: 2 5 It means that there are two threads(workers) for 5 jobs

Press enter and write the second line: 1 2 3 4 5 This is the jobs that are an integer which means the time cost of processing that job so the output after press enter will be this:

0 0 The two threads try to simultaneously take jobs from the list, so thread with index 0 actually takes the first job and starts working on it at the moment 0

1 0 Thread with index 1 takes the first job and starts working on it at the moment 0

0 1 After 1 second, thread 0 is done with the first job and takes the third job from the list, and starts processing it immediately at time 1.

1 2 One second later, thread 1 is done with the second job and takes the fourth job from the list, and starts processing it immediately at time 2

0 4 Finally, after 2 more seconds, thread 0 is done with the third job and takes the fifth job from the list, and starts processing it immediately at time 4

This is the code:

import java.io.*;
import java.util.HashMap;
import java.util.HashSet;
import java.util.PriorityQueue;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.concurrent.ConcurrentHashMap;

public class JobQueue {
    private int numWorkers;
    private int[] jobs;
    private int[] assignedWorker;
    private long[] startTime;

    private FastScanner in;
    private PrintWriter out;

    public static void main(String[] args) throws IOException {
        new JobQueue().solve();
    }

    private void readData() throws IOException {
        numWorkers = in.nextInt();
        int m = in.nextInt();
        jobs = new int[m];
        for (int i = 0; i < m; ++i) {
            jobs[i] = in.nextInt(); 
        }
    }

    private void writeResponse() {
        for (int i = 0; i < jobs.length; ++i) {
            out.println(assignedWorker[i] + " " + startTime[i]);
        }
    }

    private void assignJobs() {
        // TODO: replace this code with a faster algorithm.
        assignedWorker = new int[jobs.length];
         startTime = new long[jobs.length];
         PriorityQueue<Integer> nextTimesQueue = new PriorityQueue<Integer>();
         ConcurrentHashMap<Integer, Set<Integer>> workersReadyAtTimeT = new ConcurrentHashMap<Integer,Set<Integer>>();
         long[] nextFreeTime = new long[numWorkers];
         int duration = 0;
         int bestWorker = 0;
         for (int i = 0; i < jobs.length; i++) {
          duration = jobs[i];
          if(i<numWorkers) {
            bestWorker = i;
            nextTimesQueue.add(duration);
            addToSet(workersReadyAtTimeT, duration, i,0);
          }else {
            int currentTime = nextTimesQueue.poll();
            Set<Integer> workersReady = workersReadyAtTimeT.get(currentTime);
            if (workersReady.size()>1) { 
              bestWorker = workersReady.iterator().next();
              workersReady.remove(bestWorker);
              workersReadyAtTimeT.remove(currentTime);
              workersReadyAtTimeT.put(currentTime,workersReady);
              nextTimesQueue.add(currentTime);
            } else {
              bestWorker = workersReady.iterator().next();
              workersReadyAtTimeT.remove(currentTime);
              nextTimesQueue.add(currentTime+duration);
              addToSet(workersReadyAtTimeT, duration, bestWorker, currentTime);
            }
          }
          
          assignedWorker[i] = bestWorker;
          startTime[i] = nextFreeTime[bestWorker];
          nextFreeTime[bestWorker] += duration;
         }
        }
    
    private void addToSet(ConcurrentHashMap<Integer, Set<Integer>> workersReadyAtTimeT, int duration, int worker, int current) {
        if(workersReadyAtTimeT.get(current+duration)==null) {
          HashSet<Integer> s = new HashSet<Integer>();
          s.add(worker);
          workersReadyAtTimeT.put(current+duration, s);
        }else {
          Set<Integer> s = workersReadyAtTimeT.get(current+duration);
          s.add(worker);
          workersReadyAtTimeT.put(current+duration,s);
         }
        }

    public void solve() throws IOException {
        in = new FastScanner();
        out = new PrintWriter(new BufferedOutputStream(System.out));
        readData();
        assignJobs();
        writeResponse();
        out.close();
    }

    static class FastScanner {
        private BufferedReader reader;
        private StringTokenizer tokenizer;

        public FastScanner() {
            reader = new BufferedReader(new InputStreamReader(System.in));
            tokenizer = null;
        }

        public String next() throws IOException {
            while (tokenizer == null || !tokenizer.hasMoreTokens()) {
                tokenizer = new StringTokenizer(reader.readLine());
            }
            return tokenizer.nextToken();
        }

        public int nextInt() throws IOException {
            return Integer.parseInt(next());
        }
    }
}
 

Edit: I used a ConcurentHashMap and still launching NullPointer


回答1:


I bet this is causing some problem:

 Set<Integer> workersReady = workersReadyAtTimeT.get(currentTime);
 if (workersReady.size()>1) 
 { 
     bestWorker = workersReady.iterator().next();
     workersReady.remove(bestWorker);
     workersReadyAtTimeT.remove(currentTime);
     workersReadyAtTimeT.put(currentTime,workersReady);
     nextTimesQueue.add(currentTime);
 }

First of all, I would null-check the Set you are trying to get.

Also, if you check size()>1 it will be true when there are 2 workers ready, not only one. If you wish to check if just one is ready, the condition should be size()>0, or just !isEmpty().

Something like:

 Set<Integer> workersReady = workersReadyAtTimeT.get(currentTime);
 if (workersReady!=null && !workersReady.isEmpty()) 
 { 
     bestWorker = workersReady.iterator().next();
     workersReady.remove(bestWorker);
     workersReadyAtTimeT.remove(currentTime);
     workersReadyAtTimeT.put(currentTime,workersReady);
     nextTimesQueue.add(currentTime);
 }

You shouldn't be getting any NullPointer in this line after this, hope it helps.



来源:https://stackoverflow.com/questions/63142899/updated-code-of-nullpointerexception-problem-with-concurrenthashmap

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!