SwingWorker thread reusability - java

I wonder how java SwingWorker and it's thread pool works when some task is performed repeteadly. Here is SSCCE of problem ready to copy + paste:
package com.cgi.havrlantr.swingworkerexample;
import java.awt.*;
import javax.swing.*;
public class Main extends JFrame {
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new Main().setVisible(true);
}
});
}
public Main() {
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
setSize(new Dimension(100,100));
JButton btn = new JButton("Say Hello");
add(btn);
btn.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnPressed(evt);
}
});
}
private void btnPressed(AWTEvent e) {
SayHelloSwingWorker worker = new SayHelloSwingWorker();
worker.execute();
}
private class SayHelloSwingWorker extends SwingWorker<Integer, Integer> {
protected Integer doInBackground() throws Exception {
System.out.println("Hello from thread " + Thread.currentThread().getName());
return 0;
}
}
}
I want to ask on following. Every time I call execute() on a new instance of worker (after button is pressed), a new thread in SwingWorker thread pool is created up to 10 threads total created. After exceeding this limit, threads are reused as I expect. Because new workers are created sequentially after the previous one is finished, I don't understand, why the first thread is not reused immeadiately, because the previous worker already done it's work. Say there can be only one single thread, which does some work at the time. I would expect thread pool to create only one thread, which is enought to serve all tasks. Is this usual behaviour? Or there may be something wrong what denies reusability of the first thread and forces thread pool to create another one?
If it is normal I think it is waste of time for creation unwanted thread and memory for keeping the threads ready. Can I avoid it somehow? Can I force SwingWorker to have only one thread in his pool? - I think no, because number of threads is constant and dependent on Java implementation as far as I know.
Can I make SwingWorker to finish the thread after task was completed? (calling this.cancel() in done() method did not work)
Here is code of my real world worker, for case there is some dependency that may cause the problem.
public class MapWorker extends SwingWorker<Long, Object> {
#Override
protected Long doInBackground() throws Exception{
try {
long requestId = handleAction();
return requestId;
}catch(Exception e){
logger.error( "Exception when running map worker thread.", e);
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run(){
requestFinished();
}
});
MapUtils.showFatalError(e);
}
return -1l;
}
#Override
protected void done(){
try{
requestId = get();
logger.info("Returned from map request call, ID: {}", Long.toString(requestId));
}catch(InterruptedException e){
logger.error( "Done interrupted - wierd!", e);
}catch(ExecutionException e){
logger.error( "Exception in execution of worker thread.", e);
}
}
In method handleAction() a new thread with some blocking call is created and thread id is returned, which should not be anything weird. Don't ask me why, it is not my code. :)

Hmmm... the default ThreadPoolExecutor for SwingWorkers is configured to not only have a max pool size of 10 but also a core size of 10, meaning it prefers to keep 10 threads alive. Hard for me to tell why this is, maybe it's optimal under certain conditions.
You can tell SwingWorkers to use a custom ExecutorService using this (weird) call:
AppContext.getAppContext().put( SwingWorker.class, Executors.newSingleThreadExecutor() );
Note, the ExecutorService returned by Executors.newSingleThreadExecutor() will create a non-daemon thread, something you may want to change.

Related

Stop current Thread and then create a new thread that performs the same operation?

My problem is that I cannot figure out a way of having a thread that "on the click of a button starts, and stops on the click of another button", and then if I click the same start button a NEW thread starts that does exactly the same operation as the first. So basically just a new instance.
In my program I have a Server app that has 2 buttons and 2 text fields. After the user has entered the correct username and password the Server app opens a new ServerSocket that listens for clients that want to connect. This is done in a separate Thread to prevent the GUI from freezing. After the stop button is pressed the Thread is stopped.
How can I get my program to start a new Thread, that does the same as the first one, when I press the start button again in the GUI? Must I perhaps make use of a loop?
Server App Code:
public class Server extends JFrame implements ActionListener {
JLabel instructionsLabel;
JLabel passwordLabel;
JPasswordField passwordTF;
JButton shutdownButton;
JButton startupButton;
JLabel usernameLabel;
JTextField usernameTF;
Thread MyThread = new Thread(new ServerRunnable());
public Server() {
super("Server");
initComponents();
}
// My problem is here
public void starterMeth() {
MyThread.start();
}
public void stopMeth() {
MyThread.interrupt();
}
// in these 2 methods
public void actionPerformed(ActionEvent e) {
Object source = e.getSource();
String f = "n";
ConnectionBean cb = new ConnectionBean();
char[] a = passwordTF.getPassword();
String b = new String(a);
String inputDetails = usernameTF.getText() + b;
Iterator it = cb.getDetails().iterator();
while (it.hasNext()) {
Object next = it.next();
if (inputDetails.equals(next)) {
f = "y";
if (source == startupButton) {
if (!MyThread.isInterrupted()) {
starterMeth();
JOptionPane.showMessageDialog(null,
"Congratulations! Server started.",
"Start-up Message",
JOptionPane.INFORMATION_MESSAGE);
} else {
JOptionPane.showMessageDialog(null,
"Please restart the server application.",
"Start-up Message",
JOptionPane.INFORMATION_MESSAGE);
}
} else if (source == shutdownButton) {
stopMeth();
JOptionPane.showMessageDialog(null,
"Server shut-down successfully!",
"Shut-down Message",
JOptionPane.INFORMATION_MESSAGE);
}
// only resets the text fields when the correct details are entered
passwordTF.setText("");
usernameTF.setText("");
}
}
if (f.equals("n")) {
JOptionPane.showMessageDialog(null, "Invalid username or password.", "Alert", JOptionPane.WARNING_MESSAGE);
}
cb.setCloseConnection(true);
}
private void initComponents() {
}
}
My Runnable Code:
public class ServerRunnable implements Runnable {
#Override
public void run() {
try {
ServerSocket ss = new ServerSocket(7777);
while(true) {
Socket cs = ss.accept();
new ClientThread(cs).start();
}
} catch (IOException ex) {
}
}
}
Overview
Although the creation of a thread is valid in Java, it is highly discouraged for numerous reasons. The most significant one is that the creation of a thread is quite costly and resource intensive. In addition, there are much safer/efficient models implemented in the standard library that could be used to simplify the issue. In this particular scenario, I would advise against this implementation because of the nature of the operation; start-stop reoccurring. Note, a thread cannot be restarted once it has been started and the only way to stop a thread while executing is to call interrupt(). Unfortunately, interrupting a thread requires the developer to implement error handling in the run() method. Below we will see the run() method of a Runnable or a Thread implementation.
public void run() {
try {
// Your connection logic would be here
yourLogic();
} catch (InterruptedException ie) {
Thread.currentThread().interrupt(); // Maintain status
}
}
Lets assume you made your own thread implementation called MyThreadImpl. Below we will see how to utilize it:
public void starterMeth() {
Thread myThread = new MyThreadImpl(); // Create thread
myThread.start(); // Start execution in parallel
}
public void stopMeth() {
myThread.interrupt(); // Stop the thread
}
Alternatively if you implement your own Runnable like you are in this application, it would look like this:
public void starterMeth() {
Thread myThread = new Thread(new ServerRunnable()); // Create thread
myThread.start(); // Start execution in parallel
}
public void stopMeth() {
myThread.interrupt(); // Stop the thread
}
Although both of theses are valid, there are better approaches.
A better approach
My suggestion is to utilize the CompletableFuture class due to its robust implementation and desirable control. CompletableFutures utilize the global ForkJoinPool.common() for its threading so that the application can execute with more efficiency. In addition, you can receive the Future that is within the object for later use instead of attempting to re-create it each time. Lets investigate how this implementation would work below:
public class Server {
CompletableFuture<Void> myFuture;
...
public void starterMeth() {
myFuture = new CompletableFuture<Void>(); // Create future
myFuture.runAsync(new ServerRunnable()); // Start execution in parallel
}
public void stopMeth() {
myFuture.cancel(true); // Stop the future
}
...
}
Java does not allow to restart a Thread once it has finished executing.
Interrupting the Thread you created will simply finish its execution. The problem here is that you are using the same Thread that has finished executing (once the stop button has been clicked).
I suggest one of the following:
Improve your runnable so that when the user attempts to clicks the shutdownButton button, it stops what it was doing, and acquires some sort of semaphore to make it "sleep" until the startupButton is hit again.
(Easier) Always create a new thread on starterMeth. Don't forget to check if a Thread is running and interrupt it before starting a new thread.
I hope this helps.

How can a Thread that is asleep receive events?

My code:
public class EventHandler implements Runnable, SomeEventListener {
private static final EventHandler INSTANCE = new EventHandler();
private static final Thread THREAD = new Thread(INSTANCE);
private static volatile boolean isRunning = false;
private EventHandler () {}
private static EventHandler getInstance() {
return INSTANCE;
}
public void start() {
isRunning = true;
THREAD.start();
}
public void stop() {
isRunning = false;
}
//Listener method that was overriden
public void onEvent(Event event) {
//...do stuff
}
#Override
public void run() {
//Do nothing, let the listener do its job
while (isRunning) {
try {
logger.info("Sleeping...");
Thread.sleep(5000);
logger.info("Done sleeping...");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
Basically the run() method does nothing - just sleeps every 5 seconds, wakes up, sleeps again. What I don't understand is when it's asleep, this EventHandler class still gets events. How does this happen? Shouldn't the class stop receiving events since the thread is asleep?
The thread and the class are two different things. EventHandler is an object that has a dedicated thread executing its run method. At the same time it has its onEvent method which is available to get called by other threads.
Log the thread ID in the onEvent method and in the run method to confirm the sleeping thread is not involved in receiving events.
Classes don't own threads. Your THREAD is spinning doing its sleeping, logging, and flag-checking, while other threads in your program call onEvent. (Also the OS-level thread is a separate thing from the object whose reference you saved as THREAD.)
You could use a thread pool and that would keep your application alive until you shut it down. It would be better to submit Runnables to a thread pool than to give each Runnable its own dedicated thread.
That thread seems really useless. I don't know how you think Listeners work, but basically they are just references that some thread you probably never saw will use to call certain methods if they see something happen.
A listener does not just "catch" any events thrown into the room.
Like I said: This thread seems useless because it doesn't do anything. At all. The Events are called from a different thread. You don't need this one for it.

How to guarantee freeing of resources being used by tasks of ThreadPoolExecutor in Java

I am using ThreadPoolExecutor for pooling threads. Everytime I want to do an IO operation like writing results to a file I make use of the submit method to execute a runnable. Below is the code I have written:
**ThreadPool class looks like this:**
private static ThreadPoolExecutor executors = new ThreadPoolExecutor(8, 16, 25, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(2));;
public static void dispose(){
// end all running queues and destroy this object
executors.shutdown();
executors.shutdownNow();
}
public static void submit(Runnable r){
executors.submit(r);
}
Here is where I am submitting a runnable task to the thread pool
ThreadPool.submit(new Runnable() {
Output streamOutput = new Output(outputFileHandle.write(true));
#Override
public void run() {
if(Thread.interrupted()){
streamOutput.close();
}
writeToFile(streamOutput);
}
});
This is what happens inside WriteFile:
protected void WriteToFile(Output streamOutput){
try{
// Write to file which can take lots of time
}catch(Exception e){
// print e stack trace
}finally{
streamOutput.close();
}
}
Some threads I looked at suggested that shutdownNow() doesn't gaurantee stopping of the tasks; instead they just call .interrupt(). How should I make my Runnable handle an interrupt while its in the middle of writing to a file. Nevertheless, my objective is "to gaurantee that the stremOutput resource is closed everytime"
How should I achieve this?

Java Thread Executor Submit Main Class

I have an application with a main class that sets up a thread executor for a few other runnable classes however I want an update method in the main class to be called regularly also so is it best to create a thread like in the example below OR submit the class to the thread executor declared inside it (something like in the example below the example)?
Feels wrong using a mixture of thread executors and starting standard threads.
Use standard thread call for main classes updates?
public class Test {
private ScheduledExecutorService scheduledThreadPool; //used for creating other threads
private Thread t;
public Test() {
t = new Thread() {
#Override
public void run() {
try {
while (true) {
processUpdates();
Thread.sleep(10);
}
} catch (InterruptedException e) {
logger.error(e);
}
}
};
}
private void processUpdates() {
//do some stuff
}
}
OR use thread executor for not just the other runnable classes but the main class itself?
public class Test implements runnable {
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3);
public Test() {
scheduledThreadPool.scheduleWithFixedDelay(this, 0, 10, TimeUnit.MILLISECONDS);
}
# Override
public void run() {
processUpdates();
}
private void processUpdates() {
//do some stuff
}
}
Thanks!
Always use thread pools over plain old threads: it gives you much more control over the execution of your threads.
If you want all your threads to run in parallel, you can always use an unlimited thread pool, which is discouraged because Thread is costly in memory.
In your case, the use of a ScheduledExecutorService is even more recommended since it avoids the sleep instruction in your thread implementation. It gives better performance and a much better readability.

Java/Swing: the fast/slow UI binding problem

I need a way to bind UI indicators to rapidly-changing values.
I have a class NumberCruncher which does a bunch of heavy processing in a critical non-UI thread, thousands of iterations of a loop per second, and some number of those result in changes to a set of parameters I care about. (think of them as a key-value store)
I want to display those at a slower rate in the UI thread; 10-20Hz would be fine. How can I add MVC-style notification so that my NumberCruncher code doesn't need to know about the UI code/binding?
The idiomatic way to do this is to use the SwingWorker class, and to use calls to publish(V...) to notify the Event Dispatch thread periodically causing it to update the UI.
In the below example taken from the Javadoc the number crunching takes place on a worker thread in the doInBackground() method, which calls publish on each iteration. This call causes the process(V...) method to be called asynchronously on the Event Dispatch thread allowing it to update the UI. Note that this ensures that the user interaface is always updated from the Event Dispatch thread. Also note that you may choose to call publish every N iterations to reduce the frequency at which the user interface is updated.
Example From Javadoc
class PrimeNumbersTask extends
SwingWorker<List<Integer>, Integer> {
PrimeNumbersTask(JTextArea textArea, int numbersToFind) {
//initialize
}
#Override
public List<Integer> doInBackground() {
while (! enough && ! isCancelled()) {
number = nextPrimeNumber();
publish(number);
setProgress(100 * numbers.size() / numbersToFind);
}
}
return numbers;
}
#Override
protected void process(List<Integer> chunks) {
for (int number : chunks) {
textArea.append(number + "\n");
}
}
}
SwingWorker, suggested by #Adamski, is preferable; but an instance of javax.swing.Timer is a convenient alternative for this, as "the action event handlers for Timers execute [on] the event-dispatching thread."
Seems like you might want to take the "Listener" approach. Allow your number cruncher to register listeners, then every 100-200 loops (configurable) (or on some change condition), notify the listeners that there is an update they should be aware of.
The listener can be another class that has a thread wait() ing on it, and when it gets notified, it just updates its internal variable, then notifies the waiting thread. The fast loop class then has a quick way to update an external value and not worry about access to its fast changing internal state.
The other thread that wait()s can also have a wait() on a timer thread that is set to 10-20HZ (configurable) to wait on the timer before wait()ing on the next update from your synchronized class.
Have a single object which your NumberCrucher modifies/keeps on changing based on the numerous operations you do. Let that run in a separate thread. Have a UI in swing which uses the same Object that NumberCruncher modifies. This thread is going to only read the values at specified time period so it should not be a problem of thread deadlocks.
NumberCruncher
public class NumberCruncher implements Runnable{
CommonObject commonObj;
public NumberCruncher(CommonObject commonObj){
this.commonObj = commonObj;
}
public void run() {
for(;;){
commonObj.freqChangeVal = Math.random();
}
}
}
CommonObject:
public class CommonObject {
public double freqChangeVal;
}
UI:
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class UI extends JFrame implements Runnable{
private CommonObject commonObj = new CommonObject();
JLabel label ;
public static void main(String args[]){
UI ui = new UI();
ui.begin();
Thread t2 = new Thread(ui);
t2.start();
}
private void begin(){
JPanel panel = new JPanel();
label = new JLabel("Test");
panel.add(label);
Thread thread = new Thread(new NumberCruncher(commonObj));
thread.start();
this.add(panel);
this.setSize(200,200);
this.setVisible(true);
}
public void run() {
for(;;){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
label.setText(commonObj.freqChangeVal+"");
this.repaint();
}
}
}

Categories