JavaFX show AnchorPane from Thread - java

I am trying to create the following concept: start a thread whenever a specific screen gets launched. The thread should receive a message which is called a "tag", which is not working yet so I got it hardcoded.
Then show an AnchorPane based on the validation of the tag: either the showError or showValid function. However, the application first runs the function and then shows the AnchorPane and the updated ListView.
I want to start the following thread whenever a specific screen launches.
public class RFIDThread extends Thread{
private static final Logger logger = Logger.getLogger(RFIDApplication.class);
/**
* The incoming data stream from the LLRP reader connection
*/
private DataInputStream inStream = null;
/**
* The socket for the connection to the LLRP Reader
*/
private Socket socket = null;
/**
* A queue to store incoming LLRP Messages
*/
private LinkedBlockingQueue<LLRPMessage> queue = null;
private String[] found_tags = new String[5];
private JSONArray valid_tags;
private TagsListController controller;
/**
* Thread for constant reading of the stream
*
* #param socket
* #param controller
* #param tags
* #param orderNumber
* #throws java.io.IOException
*/
public RFIDThread(Socket socket, TagsListController controller, JSONArray tags, String orderNumber) throws IOException {
this.socket = socket;
this.controller = controller;
this.queue = new LinkedBlockingQueue<LLRPMessage>();
try {
this.inStream = new DataInputStream(socket.getInputStream());
} catch (IOException e) {
logger.error("Cannot get input stream", e);
}
valid_tags = tags;
found_tags[0] = "aga9jrjahr";
found_tags[1] = "agahs4suj";
found_tags[2] = "a79gtvaTGBQG";
found_tags[3] = "at3anit08av9agq4";
//found_tags[4] = "4a05355d0000000000017cc0";
//start();
}
#Override
public void run()
{
super.run();
if (socket.isConnected()) {
for (String found_tag : found_tags) {
Integer index = valid_tags.indexOf(found_tag);
if (index > 0) {
Platform.runLater(() -> {
controller.showValid(found_tag);
});
} else {
Platform.runLater(() -> {
controller.showError(found_tag);
});
}
}
}
}
}
The thread should run functions: showError or showValid based on the tag it receives. Currently I have some hardcoded tags set-up which are all invalid so it should run the showError() function. This function: adds the tag to a ListView, sets the tag as text of a label, display the AnchorPane, sleep 1 second, hide the AnchorPane and then sleep 1 second. After this, the next tag must be processed.
/**
* Display red screen
* #param tag
*/
public void showError(String tag) {
this.found_tags_list.getItems().add(tag);
this.errorTag.setText(tag);
System.out.println(errorTag.getText());
this.errorPane.setVisible(true);
pause(1000);
this.validPane.setVisible(false);
pause(1000);
}

You didn't post the code for your pause() method, so I'm going to assume it does something like Thread.sleep(...) and handles the interrupted exception appropriately. I.e. I'm going to assume you have something like:
public void pause(int millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException exc) {
Thread.currentThread().interrupt();
}
}
The showError() method is being (explicitly) executed on the FX Application Thread. That thread is also responsible for rendering the UI. Consequently, the UI can't be redrawn while the showError() method is executing (because a single thread can't do two things at once: that's basically the definition of "thread").
So it's always an error to block the FX Application Thread, because it makes the UI unresponsive and prevents it from being drawn.
If you are already on the FX Application Thread, and want to schedule some code to execute in the future, you can do that with a PauseTransition. So instead of
this.errorPane.setVisible(true);
pause(1000);
this.validPane.setVisible(false);
you can do
this.errorPane.setVisible(true);
PauseTransition pause = new PauseTransition(Duration.millis(1000));
pause.setOnFinished(e -> this.validPane.setVisible(false));
pause.play();
The second pause in that method makes less sense. It simply pauses the FX Application Thread, and then the method exits, so there is nothing it is waiting for anyway.
If the idea is to make the background thread pause at that point, you should call pause() on the background thread. (Calling it on the FX Application Thread, obviously, won't make the background thread pause anyway.)
So I think your code should look like:
public class RFIDThread extends Thread {
// ...
#Override
public void run() {
super.run();
if (socket.isConnected()) {
for (String found_tag : found_tags) {
Integer index = valid_tags.indexOf(found_tag);
if (index > 0) {
Platform.runLater(() -> controller.showValid(found_tag));
} else {
Platform.runLater(() -> controller.showError(found_tag));
}
pause(2000);
}
}
}
}
Note that I'm guessing here the intention is for your background thread to pause for (approximately) one second after the pane you show is hidden again, which would mean it needs to pause for two seconds in total.
In the controller, you do
public void showError(String tag) {
this.found_tags_list.getItems().add(tag);
this.errorTag.setText(tag);
System.out.println(errorTag.getText());
this.errorPane.setVisible(true);
PauseTransition pause = new PauseTransition(Duration.millis(1000));
pause.setOnFinished(e -> this.validPane.setVisible(false));
pause.play();
}

Related

A thread that runs without stopping

Is it possible in java to create a thread that will always work in the background? The problem is that the application instance sometimes crashes with an OutOfMemoryException. Therefore, several instances are launched in parallel. Each instance does some work: it saves something to the database at the request of the user. And the stream, which should work constantly, will look into the database and somehow process the information from it.
Most likely, the sheduler will not work, since the thread must be running constantly and wait for a signal to start working.
First of all, I suggest you investigate and resolve the OutOfMemoryException because it better to avoid these cases. You can instanziate a thread that wait for a request, execute a request and then return to wait for another request. The implementation is like this for thread:
/** Squares integers. */
public class Squarer {
private final BlockingQueue<Integer> in;
private final BlockingQueue<SquareResult> out;
public Squarer(BlockingQueue<Integer> requests,
BlockingQueue<SquareResult> replies) {
this.in = requests;
this.out = replies;
}
public void start() {
new Thread(new Runnable() {
public void run() {
while (true) {
try {
// block until a request arrives
int x = in.take();
// compute the answer and send it back
int y = x * x;
out.put(new SquareResult(x, y));
} catch (InterruptedException ie) {
ie.printStackTrace();
}
}
}
}).start();
}
}
And for the caller method:
public static void main(String[] args) {
BlockingQueue<Integer> requests = new LinkedBlockingQueue<>();
BlockingQueue<SquareResult> replies = new LinkedBlockingQueue<>();
Squarer squarer = new Squarer(requests, replies);
squarer.start();
try {
// make a request
requests.put(42);
// ... maybe do something concurrently ...
// read the reply
System.out.println(replies.take());
} catch (InterruptedException ie) {
ie.printStackTrace();
}
}
To more information, you can start to read the post that I found here to provide you the example.
You basically need an infinitely running thread with some control.
I found this answer to be the simplest and it does what you need.
https://stackoverflow.com/a/2854890/11226302

JavaFX splash screen message and progress not updating

I have a JavaFX application that checks for the presence of a database at startup. If the database is not found, a "seed" database must be created before the program can proceed.
Since creating the seed database can be lengthy, I want to display a splash screen and show progress updates as the process proceeds. Only after the seed database is completely written should the program proceed.
Here is the class for the splash screen:
public final class SplashWindow {
private final Label message;
private final ProgressBar progress;
private final Stage splashStage;
public SplashWindow() {
Image img = new Image(IMAGE_PREFIX + "splash_image.png");
double imgWidth = img.getWidth();
ImageView splashImage = new ImageView(img);
splashImage.setFitWidth(imgWidth);
splashImage.setPreserveRatio(true);
message = new Label("Saving seed database...");
message.setPrefWidth(imgWidth);
message.setAlignment(Pos.CENTER);
progress = new ProgressBar();
progress.setPrefWidth(imgWidth);
Pane splashVBox = new VBox(3);
splashVBox.setPadding(new Insets(5));
splashVBox.getChildren().addAll(splashImage, progress, message);
splashStage = new Stage(StageStyle.UTILITY);
splashStage.setScene(new Scene(splashVBox));
}
public void bindMessageProperty(ReadOnlyStringProperty sp) {
message.textProperty().bind(sp);
}
public void bindProgressProperty(ReadOnlyDoubleProperty dp) {
progress.progressProperty().bind(dp);
}
public void show() {
splashStage.show();
}
public void shutdown() {
message.textProperty().unbind();
progress.progressProperty().unbind();
splashStage.hide();
}
}
When run, the splash screen shows correctly with the image, progress bar and text message area.
The SplashWindow class is called by the following method:
private void saveSeedDatabase(ObservableList<RefModel> docList) {
SplashWindow splash = new SplashWindow();
Task<Integer> saveTask = new Task<Integer>() {
#Override
protected Integer call() throws InterruptedException {
updateMessage("Saving references...");
int docsSaved = 0;
for (RefModel rm : docList) {
if (isCancelled()) {
updateMessage("Cancelled");
break;
}
updateMessage("Saving: " + rm.getTitle());
saveNewReference(rm);
docsSaved++;
updateProgress(docsSaved, docList.size());
}
updateMessage("Saved " + docsSaved + " references to database");
return docsSaved;
}
};
saveTask.setOnSucceeded((WorkerStateEvent t) -> {
splash.shutdown();
});
splash.bindMessageProperty(saveTask.messageProperty());
splash.bindProgressProperty(saveTask.progressProperty());
splash.show();
new Thread(saveTask).start();
try {
saveTask.get();
} catch (InterruptedException | ExecutionException ex) {
// Do nothing
}
}
When run, the splash screen is displayed but never shows the update messages and progress. It shows a wait cursor when the mouse if over the splash screen.
If the try/catch block at the end of the method is commented out, the main program attempts to proceed without waiting for the database to be written. In this case, the splash screen is hidden by the main program window, but does display the update messages as it works. From debugging this, it looks like everything is running on the correct thread -- the database stuff is on a worker thread, the SplashWindow stuff is on the FX event thread.
It seems clear that the call to saveTask.get() is blocking the UI thread, but I am not sure why.
#JewelSea has written a nice alternative that doesn't fit my program architecture very well. It would not be impossible to alter my program to work with his solution.
However, I don't understand why the get() call blocks the UI. What am I doing wrong.
According to the JavaDocs:
(get()) Waits if necessary for the computation to complete, and then retrieves its result.
Retrieving the computed value without blocking the GUI Thread would be done with getValue(). However: This method only returns a result, when the Task has successfully finished its work. That is why you should do this aysnc in the onSucceeded block.

java.util.AbstractList$Itr.checkForComodification Triple Events

I run a server and it has an event handler that handles a timing system
When I run 3 of them in a row, it gives this exception
Exception in thread "Thread-8" java.util.ConcurrentModificationException
at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
at java.util.AbstractList$Itr.next(AbstractList.java:343)
at EventManager.run(EventManager.java:77)
at java.lang.Thread.run(Thread.java:662)
here's the method that the issue is coming from:
EventManager.getSingleton().addEvent( new Event() {
public void execute(EventContainer c) {
p.createProjectile(p.absY, p.absX, offsetY, offsetX, 1166, 43, 31, 70, p2.playerId);
c.stop(); // stops the event from running
}
}, 950); // in ms (1 second = 1000 ms)
EventManager.getSingleton().addEvent( new Event() {
public void execute(EventContainer c) {
p2.applyDAMAGE(misc.random(25));
c.stop(); // stops the event from running
}
}, 1300); // in ms (1 second = 1000 ms)
p.secondsTillNextDfsSpecial = 120;
EventManager.getSingleton().addEvent( new Event() {
public void execute(EventContainer c) {
p.secondsTillNextDfsSpecial--;
if (p.secondsTillNextDfsSpecial == 0) {
p.canPerformDfsSpecial = true;
c.stop(); // stops the event from running
}
}
}, 1000); // in ms (1 second = 1000 ms)
import java.util.ArrayList;
import java.util.List;
/**
* Manages events which will be run in the future.
* Has its own thread since some events may need to be ran faster than the cycle time
* in the main thread.
*
* #author Graham
*
*/
public class EventManager implements Runnable {
/**
* A reference to the singleton;
*/
private static EventManager singleton = null;
/**
* A list of events that are being executed.
*/
private List<EventContainer> events;
/**
* Initialise the event manager.
*/
private EventManager() {
events = new ArrayList<EventContainer>();
}
/**
* The event manager thread. So we can interrupt it and end it nicely on shutdown.
*/
private Thread thread;
/**
* Gets the event manager singleton. If there is no singleton, the singleton is created.
* #return The event manager singleton.
*/
public static EventManager getSingleton() {
if(singleton == null) {
singleton = new EventManager();
singleton.thread = new Thread(singleton);
singleton.thread.start();
}
return singleton;
}
/**
* Initialises the event manager (if it needs to be).
*/
public static void initialise() {
getSingleton();
}
/**
* The waitFor variable is multiplied by this before the call to wait() is made.
* We do this because other events may be executed after waitFor is set (and take time).
* We may need to modify this depending on event count? Some proper tests need to be done.
*/
private static final double WAIT_FOR_FACTOR = 0.5;
#Override
/**
* Processes events. Works kinda like newer versions of cron.
*/
public synchronized void run() {
long waitFor = -1;
List<EventContainer> remove = new ArrayList<EventContainer>();
while(true) {
// reset wait time
waitFor = -1;
// process all events
for(EventContainer container : events) {
if(container.isRunning()) {
if((System.currentTimeMillis() - container.getLastRun()) >= container.getTick()) {
container.execute();
}
if(container.getTick() < waitFor || waitFor == -1) {
waitFor = container.getTick();
}
} else {
// add to remove list
remove.add(container);
}
}
// remove events that have completed
for(EventContainer container : remove) {
events.remove(container);
}
remove.clear();
// no events running
try {
if(waitFor == -1) {
wait(); // wait with no timeout
} else {
// an event is running, wait for that time or until a new event is added
int decimalWaitFor = (int)(Math.ceil(waitFor*WAIT_FOR_FACTOR));
wait(decimalWaitFor);
}
} catch(InterruptedException e) {
break; // stop running
}
}
}
/**
* Adds an event.
* #param event The event to add.
* #param tick The tick time.
*/
public synchronized void addEvent(Event event, int tick) {
events.add(new EventContainer(event,tick));
notify();
}
/**
* Shuts the event manager down.
*/
public void shutdown() {
this.thread.interrupt();
}
}</code></pre>
Ok, I see two problems:
Your events List is not synchronized and you are accessing it from different threads (one in EventManager and second in the first piece of code with addEvent()).
In this loop:
// process all events
for(EventContainer container : events) {
...
}
you are iterating over events List and you cannot add new elements to it while iteration. I assume addEvent() is adding new elements to this list, so basically you shouldn't call it during this iteration.
Both of this problems can be solved by using CopyOnWriteArrayList which enables safe access by concurrent threads and safely adding new elements during iteration (however new elements will be "visible" only in next iteration).
Solution:
private EventManager() {
events = new CopyOnWriteArrayList() ;
}

Image processing in a multhithreaded mode using Java

I am supposed to process images in a multithreaded mode using Java. I may having varying number of images where as my number of threads are fixed. I have to process all the images using the fixed set of threads.
I am just stuck up on how to do it, I had a look ThreadExecutor and BlockingQueues etc...I am still not clear. What I am doing is,
- Get the images and add them in a LinkedBlockingQueue which has runnable code of the image processor.
- Create a threadpoolexecutor for which one of the arguements is the LinkedBlockingQueue earlier.
- Iterate through a for loop till the queue size and do a threadpoolexecutor.execute(linkedblockingqueue.poll).
- all i see is it processes only 100 images which is the minimum thread size passed in LinkedBlockingQueue size.
I see I am seriously wrong in my understanding somewhere, how do I process all the images in sets of 100(threads) until they are all done? Any examples or psuedocodes would be highly helpful
Thanks!
J
Here is a sample class that I wrote. The whole thing runs standalone and prints a number from 1 to 100 each from a ThreadPool. Pretty much all you need to do is update the Request class to pass in what you want and to re-implement ImageProcessor.
package com.rch.test;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
public class Executor
{
/**
* Class to encapsulate a request
*
* #author romain
*/
static class Request
{
String someText;
Request(String someText)
{
this.someText = someText;
}
public String getSomeText()
{
return someText;
}
}
/**
* Creates a Thread that listens on a queue to process messages
*
* #author romain
*/
static class ServerThread implements Runnable
{
private BlockingQueue<Request> queue = new LinkedBlockingQueue<Request>();
boolean stop = false;
/**
* Does all the work
*/
#Override
public void run()
{
ExecutorService pool = Executors.newFixedThreadPool(3);
try
{
while (!stop)
{
Request req = queue.poll(1000L, TimeUnit.MILLISECONDS);
if (req != null)
{
Runnable runnable = new Executor.ImageProcessor(req);
pool.execute(runnable);
}
}
}
catch (InterruptedException ie)
{
System.out.println("Log something here");
}
finally
{
pool.shutdown();
}
}
/**
* Accepts a message on the queue
* #param request
*/
public void accept(Request request)
{
queue.add(request);
}
public void stopProcessing()
{
stop = true;
}
}
/**
* class to do the actual work
* #author romain
*/
static class ImageProcessor implements Runnable
{
String someText;
ImageProcessor(Request req)
{
this.someText = req.getSomeText();
}
#Override
public void run()
{
System.out.println(someText);
// Process Image here
}
}
/**
* Test Harness
* #param args
*/
public static void main(String[] args)
{
// Initialize
ServerThread processor = new ServerThread();
Thread aThread = new Thread(processor);
aThread.start();
// Wait for Thread to start
try
{
Thread.sleep(500L);
}
catch (InterruptedException e1)
{
e1.printStackTrace();
}
for (int i = 0; i < 100; i++)
{
String text = "" + i;
Request aRequest = new Request(text);
processor.accept(aRequest);
}
// Give it enough time to finish
try
{
Thread.sleep(500L);
}
catch (InterruptedException e1)
{
e1.printStackTrace();
}
// Tell the thread to finish processing
processor.stopProcessing();
// Wait for the Thread to complete
try
{
aThread.join();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
You can think of each processing operation being a 'task'. Place these tasks in a single queue, and have each thread consuming a task from this thread each time they complete a task.
Sun's tutorials is really good so i will just post the link Defining and Starting a Thread
Quote:
Threads are sometimes called lightweight processes. Both processes and threads provide an execution environment, but creating a new thread requires fewer resources than creating a new process.
Threads exist within a process — every process has at least one. Threads share the process's resources, including memory and open files. This makes for efficient, but potentially problematic, communication.
while(que is not empty)
start new set of image-processing-thread

What is the best approach to handling exceptions thrown in a separate thread?

I am working on a J2ME project that spawns worker threads for numerous tasks such as downloading HTTP content. The basic thread layout is similar to most java apps--there is a main UI thread and worker threads spawned to do stuff behind the scenes. My question is what is the best way to handle exceptions that occur in the worker threads?
I usually adhere to the design rationale that most exceptions should be percolate as far as possible. When I write single threaded apps, it is common for me to percolate the exceptions all the way up to the UI layer and then report them in an error dialog to the user. Is there a similar practice for multithreaded apps? The most intuitive thing to me is to catch exceptions in the Thread.run() and then call an invokeLater on the UI thread to report it in a dialog. The issue I see here is that outside of the worker thread dying off prematurely, this approach does not really notify the UI thread there was an error. I do not see a clear way to throw an exception across threads so to speak.
Thanks,
Andy
You should NOT jam UI code into your workers!
/**
* TWO CHOICES:
* - Monitor your threads and report errors,
* - setup a callback to do something.
*/
public class ThreadExceptions {
/** Demo of {#link RunnableCatch} */
public static void main(String[] argv) throws InterruptedException {
final Runnable bad = new NaughtyThread();
// safe1 doesnt have a callback
final RunnableCatch safe1 = new RunnableCatch(bad);
// safe2 DOES have a callback
final RunnableCatch safe2 = new RunnableCatch(bad, new RunnableCallback() {
public void handleException(Runnable runnable, Exception exception) {
System.out.println("Callback handled: " + exception.getMessage());
exception.printStackTrace();
}
});
final Thread t1 = new Thread(safe1, "myThread");
final Thread t2 = new Thread(safe2, "myThread");
t1.start();
t2.start();
t1.join();
t2.join();
if (safe1.getException() != null) {
System.out.println("thread finished with exceptions");
safe1.getException().printStackTrace();
}
System.out.println("done");
}
}
/** Throws an exception 50% of the time */
class NaughtyThread implements Runnable {
public void run() {
try {
if (Math.random() > .5) {
throw new RuntimeException("badness");
}
} finally {
System.out.println("ran");
}
}
}
/** Called when an exception occurs */
interface RunnableCallback {
void handleException(Runnable runnable, Exception exception);
}
/**
* Catches exceptions thrown by a Runnable,
* so you can check/view them later and/or
* deal with them from some callback.
*/
class RunnableCatch implements Runnable {
/** Proxy we will run */
private final Runnable _proxy;
/** Callback, if any */
private final RunnableCallback _callback;
/** #guarded-by(this) */
private Exception _exception;
public RunnableCatch(final Runnable proxy) {
this(proxy, null);
}
public RunnableCatch(final Runnable proxy, RunnableCallback target) {
_proxy = proxy;
_callback = target;
}
public void run() {
try {
_proxy.run();
} catch (Exception e) {
synchronized (this) {
_exception = e;
}
if (_callback != null) {
_callback.handleException(_proxy, e);
}
}
}
/** #return any exception that occured, or NULL */
public synchronized Exception getException() {
return _exception;
}
}
Another option other than what Stuph has given is to set exceptions in the thread local. If another exception happens before that exception is cleared then an assert occurs. That at least gives someone a chance to notice the exception and process it.

Categories

Resources