Class ExportingFiles

java.lang.Object
real_time_traffic_simulation_with_java.tools.ExportingFiles

public class ExportingFiles extends Object
Handles CSV export on a background thread.

Main thread queues data, worker thread writes to file. Thread components for exporting CSV data in the background.

ExecutionService is an Executor that provides methods to manage termination and methods that can produce a Future for tracking progress of one or more asynchronous tasks.

BlockingQueue is a Queue that additionally supports operations that wait for the queue to become non-empty when retrieving an element, and wait for space to become available in the queue when storing an element.

We choose BlockingQueue because it is thread-safe (i.e. multiple threads can access it concurrently) and it handles synchronization internally. Normal queues like LinkedList are not thread-safe and would require additional synchronization mechanisms (like synchronized blocks) to ensure safe concurrent access, which can be error-prone and less efficient.

The combination of ExecutorService and BlockingQueue allows us to efficiently manage background tasks and safely share data between threads.

private volatile boolean is used to ensure that changes to the running flag are immediately visible to all threads. This is important for safely stopping the background worker thread when shutting down the export service. If we did not use volatile, there is a risk that the worker thread might not see the updated value of running in a timely manner, or might cache old values, leading to potential issues during shutdown.

More note about BlockingQueue: A BlockingQueue is typically used to have one thread produce objects, which another thread consumes. The producing thread will keep producing new objects and insert them into the BlockingQueue, until the queue reaches some upper bound on what it can contain. Its limit, in other words.

If the blocking queue reaches its upper limit, the producing thread is blocked while trying to insert the new object. It remains blocked until a consuming thread takes an object out of the queue.

The consuming thread keeps taking objects out of the BlockingQueue to process them. If the consuming thread tries to take an object out of an empty queue, the consuming thread is blocked until a producing thread puts an object into the queue.

See Also:
  • Constructor Details

    • ExportingFiles

      public ExportingFiles()

      Create ExportingFiles with background worker thread. First it initializes the CSV manager and thread components, then starts the worker thread.

      We use a LinkedBlockingQueue with a capacity of 1000 to buffer data between the main thread and the worker thread. This allows the main thread to queue data quickly without blocking, while the worker thread processes the data at its own pace. LinkedBlockingQueue is an optionally-bounded blocking queue based on linked nodes. This queue orders elements FIFO.

      newSingleThreadExecutor is Executor method that Creates an Executor that uses a single worker thread operating off an unbounded queue, and uses the provided ThreadFactory to create a new thread when needed.

      We use a single-threaded executor to ensure that CSV writes are performed sequentially, preventing potential data corruption from concurrent writes. For example, if multiple threads tried to write to the CSV file at the same time, it could lead to interleaved data and an invalid file format. Furthermore, because this is a background thread, it won't block the main simulation thread, ensuring smooth performance and take less system resources.

      We then set the running flag to true to indicate that the worker thread should continue running. Then start the background worker thread by calling startWorker(), which submits a task to the executor that continuously polls the queue for new data and writes it to the CSV file.

      See Also:
  • Method Details

    • queueCSV

      public void queueCSV(List<String[]> vehicleData)

      Queue vehicle data for CSV export (non-blocking). The data is from the simulation engine (called in the main window), then put into the queue for background export ReportData object is created and added to the queue.

      If the queue is full, a warning is logged and the data is dropped. If not we use offer() method to add data to the queue because it is non-blocking. This means that if the queue is full, the method will return false immediately instead of blocking the calling thread until space becomes available.

      Parameters:
      vehicleData - Data to write to CSV
    • getCSVFilePath

      public String getCSVFilePath()
      Get the file path of the current CSV file.
      Returns:
      CSV file path
    • getCSVTimerstamp

      public String getCSVTimerstamp()
      Get the timestamp of the current CSV file for PDF export.
      Returns:
      CSV timestamp
    • shutdown

      public void shutdown()
      Shutdown the export service. Waits for queued data to be written.