0

I'm working on a JavaFX application. I have several JSON files which I would like to read and insert into Collections in domain objects. I am using Gson to read these files at present. My application currently is working, however, there is a long delay before the application launches. I assume that this is because I'm reading these files sequentially and in the same Thread. Therefore, I am looking to enhance the launch time by introducing some concurrency. I'm thinking If I can figure out how to read the files in parallel it should speed up the launch time. I'm new to the idea of concurrency so I'm trying to learn as I go. Needless to say, I've hit a few roadblocks and can't seem to find much information or examples online.

Here are my issues:

  1. Not sure if the JSON file reads can be done in a background thread.

Domain classes use these Collections to compute and eventually display values in the GUI. From my understanding, if you modify the GUI it has to be done in the JavaFX Application thread and not in the background. I'm not sure if loading data to be used in the GUI counts as modifying the GUI. I'm not directly updating any GUI Nodes like textField.setText("something") by reading Json, so I would assume no, I'm not. Am I wrong?

  1. What is the difference between a Task> and Thread or an ExecutorService and Callable>? Is one method preferred over the other? I've tried both and failed. When I tried using a task and background thread, I would get a NullPointerException because the app tried to access the collection before the files were read and initialized with data. It went from being too slow to being too fast. SMH.

  2. To solve this problem, I heard about Preloaders. The idea here was to launch some sort of splash screen to delay until the loading of resources (reading of JSON files) was complete, then proceed to the main application. However, the examples or information here is VERY scarce. I'm using Java 10 and IntelliJ, so I may have cornered myself into a one in a million niche.

I'm not asking for anyone to solve my problem for me. I'm just a little lost and don't know where or how to proceed. I'll be happy to share specifics if needed but I think my issues are still conceptual at this point.

Help me StackOverflow you're my only hope.

edit: code example:

public class Employee {

  private List<Employee> employeeList;

  public Employee() {
    employeeList = new ArrayList<>();
    populateEmployees();
  }

  private final void populateEmployees() {
    Task<Void> readEmployees = new Task<>() {
      @Override
      protected Void call() throws Exception {
        System.out.println("Starting to read employee.json"); // #1
        InputStream in = getClass().getResourceAsStream("/json/employee.json");
        Reader reader = new InputStreamReader(in);
        Type type = new TypeToken<List<Employee>>(){}.getType();
        Gson gson = new Gson();
        employeeList.addAll(gson.fromJson(reader, type));
        System.out.println("employeeList has " + employeeList.size() + " elements"); // #2
        return null;
      }
    };
    readEmployees.run();
    System.out.println(readEmployees.getMessage());  // #3
  }
}

I see #1 printed to the console, never #2 or 3. How do I know that it processed all through the Task?

Frijolie
  • 83
  • 1
  • 6
  • 1
    The question seems a bit broad in its current form. You're likely to get better answers if you share an (minimal but verifiable) example of your current code. We would need to understand what exactly is slow in order to suggest improvements. – Mick Mnemonic Jul 24 '18 at 18:34
  • Make your `populateEmployees` return the `Task` `readEmployees `. Then in your `Controller` or `Main` do `Employee employee = new Employee ();` `new Thread(employee.populateEmployees()).start();`. The code may not be 100% correct, but the ideas is. – SedJ601 Jul 25 '18 at 03:44

1 Answers1

1

How much your app will speed up depends on how big are those files and how much files there are. You should know that creating threads is also resource consuming task. I can imagine situation where you have plenty of files and for each one you're creating a new thread which could even make your app initialize slower. In case of big amount of files or number of files which can change in time, you can arrange some thread pool of constant number eg. 5 which can work simultaneously on reading files task. Back to the problem and the question is it worth to use separate threads for reading files, I'll say yes but only if your app have some work on initialization which can be done without knowing content of those files. You should be aware that in some point in time you'll probably need to wait for file parsing results.

As a part of problem solving you can do some benchmark to check how long parsing each file process takes and then you'll know what configuration/amount of working threads will be the best. Eg. you won't create thread for each file when parsing takes 1 second, but if you have 100 files of 1 second processing time you can create some thread pool and divide the job for each thread equally.

  1. yes

  2. I don't know JavaFX but in general concept of Thread and Task is the same. Thread gives you certanity that you're starting new thread, it's lower level of abstraction. Task is some sort of higher abstraction where you want to run part of your code separately, and asynchronously but you don't want to be aware on which thread it will run. Some programming languages behind Task hides actually some thread pool.

  3. Preloaders are fine, because they show user some job is being done in background so he won't worry if application has frozen. On the other hand if you can speed up initialization process it will be great. You can join those two ideas, but remember, no one wants to wait a lot :)

  • Forgot, When I run my run it as a task, I get error: java.lang.IllegalStateException: Task must only be used from the FX Application Thread – Frijolie Jul 24 '18 at 19:55