I have a Java program that writes to a file whenever a user does a certain action. To avoid blocking the main thread I thought it would be best to handle writing to that file on a separate thread. Anyways I am wondering what's the best way to go about that. At first I created a new object that implements Runnable. Then when ever I needed to write to a file I created a new instance of that object and a new thread, passed in the runnable as a parameter to the thread and started it. This works fine however I was not sure if this was the best approach and based on my research apparently creating a new thread object is very memory intensive.
final UpdateConfigRunnable runnable = new UpdateConfigRunnable(stringData, object);
final Thread thread = new Thread(runnable);
thread.start();
Normally I was passing in an object (all data being queried from that object is final) and some string data into the constructor of my runnable object. One issue is I cant generate a new runnable and pass it into the same thread which means I need to make the thread once and the runnable once then maybe update stringData with a setter method before I call the start method? That implantation would look like this.
public class NormalClass {
final UpdateConfigRunnable runnable;
final Thread thread;
public NormalClass(Object object) {
runnable = new UpdateConfigRunnable(object);
this.thread = new Thread(runnable);
}
public void updateFile(String data) {
runnable.setData(data);
thread.start();
}
}
In the above implementation "NormalClass" is only ever accessed / called by one single thread. Calling the updateFile() method would then change the value of stringData inside the runnable object before I start the thread with the start() method. Is this the second example the correct way to go about this if not what did I get wrong about using multiple threads in this scenario?
Edit: Let me know if the following implementation of blocking queue is correct.
public class UpdateConfigRunnable implements Runnable {
private final BlockingQueue<ScreenGui> blockingQueue;
public UpdateConfigRunnable(final BlockingQueue<ScreenGui> blockingQueue) {
this.blockingQueue = blockingQueue;
}
@Override
public void run() {
while(true) {
try {
final ScreenGui screenGui = blockingQueue.take();
final int sizeOfFont = screenGui.getSizeOfFont();
final String font = screenGui.getFontName();
//I will handle writing to the file here
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Now here is the class which will be adding to queue. Here you can see I am actually adding a reference of this ScreenGui since that contains an object which I need to reference in order to obtain 2 final variables. Then I also need to pass in an this's instance of ScreenGui since in order for the runnable to have access sizeOfFont and fontName which I marked volatile since I want to keep those variables in ram to avoid compiler optimization (the values may be updated in cache but not in ram when viewed from the other thread). I could instead of passing in ScreenGui make a separate object which contains everything I need but I am not sure if generating a new object just for that is more optimized than just saving a larger object in memory aka ScreenGui.
final BlockingQueue<ScreenGui> blockingQueue;
final UpdateConfigRunnable runnable;
final Thread fileSaverThread;
private volatile String fontName;
private volatile int sizeOfFont;
public ScreenGui() {
this.blockingQueue = new LinkedBlockingQueue<>();
this.runnable = new UpdateConfigRunnable(blockingQueue);
this.fileSaverThread = new Thread(runnable);
fileSaverThread.setDaemon(true);
fileSaverThread.start();
}
public void saveFile() {
try {
blockingQueue.put(this);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Also since the thread is a daemon thread I assume making an infinite while loop is fine inside of the runnable.