0

I have thread pool that i'm trying to shutdown but i'm getting the following error:

java.lang.NullPointerException
    at Terminate.action(Terminate.java:8)
    at Event.run(Event.java:63)
    at java.base/java.lang.Thread.run(Thread.java:832)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:630)
    at java.base/java.lang.Thread.run(Thread.java:832)

the thread pool is defined in Restart() extends Event:

public class Restart extends Event {
    private static String eventsFile;
    ArrayList<String> eventList = new ArrayList<>();
    ArrayList<Integer> timeList = new ArrayList<>();
    public int rings = 1;
    GreenhouseControls greenhouseControls = new GreenhouseControls();

    public Restart(long delayTime, String filename) {
        super(delayTime);
        eventsFile = filename;
    }

    // action was modified to read text file and add events indicated in file
    public void action() {
        File file = new File(eventsFile);
        try {
            Scanner scanner = new Scanner(file);
            while(scanner.hasNext()){
                String eventLine = scanner.nextLine();

                // Using regex to identify events, delay time and number of rings in txt file
                Pattern pattern = Pattern.compile("^Event=(?<event>[^,]*),time=(?<time>[^,]*)(,rings=(?<ring>[^,]*))?$");
                Matcher matcher = pattern.matcher(eventLine);
                // store delay time and number of rings in their respective variables.
                while (matcher.find()) {
                    String eventName = matcher.group("event");
                    int time = Integer.parseInt(matcher.group("time"));

                    if (matcher.group("ring") != null) {
                        rings = Integer.parseInt(matcher.group("ring"));
                    }

                    eventList.add(eventName);
                    timeList.add(time);
                }
            }
        }

        catch (FileNotFoundException e) {
            e.printStackTrace();
        }

        pool = Executors.newFixedThreadPool(timeList.size());

        for (int i = 0; i < eventList.size(); i++) {
            Class<?> eventClass;

            try {
                eventClass = Class.forName(eventList.get(i));
                Object eventObject;
                if (eventList.get(i).equals("Bell")) {
                    eventObject = eventClass.getConstructor(long.class, int.class).newInstance(timeList.get(i), rings);
                }

                else {
                    eventObject = eventClass.getConstructor(long.class).newInstance(timeList.get(i));
                }

                Thread eventThread = new Thread((Runnable) eventObject);
                //eventThread.start();
                pool.execute(eventThread);
            }

            catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException e) {
                e.printStackTrace();
            }
        }

        System.out.println(pool);
    }

    public String toString() {
        return "Restarting system";
    }
}

and the shutdown is being called here:

public class Terminate extends Event {

    public Terminate(long delayTime) {
        super(delayTime);
    }

    public void action() {
        pool.shutdown();
    }
    public String toString() {
        return "Terminating";
    }
}

Event.java:

public abstract class Event implements Runnable {
  private long eventTime;
  protected final long delayTime;
  public ExecutorService pool;
  GreenhouseControls greenhouseControls = new GreenhouseControls();
  public String errorMessage;
  boolean suspend;

  public Event(long delayTime) {
    this.delayTime = delayTime;
    start();
  }

  public void start() { // Allows restarting
    eventTime = System.currentTimeMillis() + delayTime;
  }

  public boolean ready() {
    return System.currentTimeMillis() >= eventTime;
  }

  public synchronized void isSuspended() {
    suspend = greenhouseControls.getSuspend();
    notifyAll();
  }

  public void run() {
    try {
      while (suspend) {
        try {
          synchronized(this) {
            wait();
          }
        }

        catch (InterruptedException e) {
          e.printStackTrace();
        }
      }

      Thread.sleep(delayTime);
    }

    catch (InterruptedException e) {
      pool.shutdown();
    }

    try {
      System.out.println(this.toString());
      this.action();
    }

    catch (Exception e) {
      e.printStackTrace();
    }
  }

  public abstract void action() throws GreenhouseControls.ControllerException;
} ///:~

I'm not really sure what's causing it and tried changing how the pool is defined and where I call shutdown but nothing really changed. any idea what's causing it and how to fix it?

Thanks in advance.

dxbh0517
  • 41
  • 7
  • Where is your 'pool' gets its initialized value inside your Terminate class?? While calling action() can you try to pass pool ref to it?? – Sabareesh Muralidharan Jun 29 '20 at 02:43
  • the initialized value of pool in in Restart (the one right after the error). is the what you mean? also pool is declared in Event() (the super class of both Restart and Terminate. – dxbh0517 Jun 29 '20 at 02:48
  • Hmm.. Jus try to print the value of pool and check if it is non null – Sabareesh Muralidharan Jun 29 '20 at 02:52
  • so i ran 2 print statments one in Restart() that gave me this `[Running, pool size = 8, active threads = 7, queued tasks = 0, completed tasks = 1]` and one in Terminate() before the shutdown that was `null` – dxbh0517 Jun 29 '20 at 02:58
  • Please provide the complete code of Event, Restart & Terminate class for reference. – Govind Jun 29 '20 at 03:04
  • @Govind I added Event and the rest of Restart. and that was the full code of Terminate. – dxbh0517 Jun 29 '20 at 03:07

1 Answers1

0
Question: Why `NullPointerException` was thrown?

Well, in your abstract class Event you have declared your ExecutorService

public ExecutorService pool;

But among those two child classes Terminate and Restart, the pool was initialized only in Restart but in Terminate it is still pointing to null

So, when you try to call action the ref to pool was null and hence NullPointerException was thrown.

Instead,

Initialize and assign the value to ExecutorService in your abstract class itself and share the pool to your child classes.

public abstract class Event implements Runnable {
  ...
  public ExecutorService pool;
  ...
  public void setExecutorService(int size) {
    pool = Executors.newFixedThreadPool(size);
  }
}

public class Restart extends Event {
  ...
  setExecutorService(timeList.size());
  ...
}