During my Unit tests, I'd like to plot some figures using Java FX. Now the problem is that as soon as the Unit test are done, the JVM and thus Java FX shut down and I am not able to inspect the generated plots (unlike in the case where the "test" is just started from the main method). So my question is, is there a way to stop JUnit from exiting before particular threads are finished, i.e. to replicate the behaviour as the test is started from the main method directly? And yes, I am aware that plotting is most likely not really something which should be done during a unit test in general.
At the moment I am doing something like this:
//#ContextConfiguration(classes = {DummyConfig.class })
//#RunWith(SpringJUnit4ClassRunner.class)
public class MainViewTest {
private boolean fromMain = false;
// starting the "test" from main does not require explicit waiting for
// for the JavaFX thread to finish .. I'd like to replicate this
// behaviour in JUnit (by configuring JUnit, not my test or application code)
public static void main(String [] args){
new MainViewTest(true).test();
}
public MainViewTest(){}
private MainViewTest(boolean fromMain){
this.fromMain = fromMain;
}
#Test
public void test() {
//do some tests....
//plot some results...
PlotStage.plotStage(new QPMApplication() {
#Override
public Stage createStage() {
Stage stage = new Stage();
StackPane root = new StackPane();
Scene scene = new Scene(root, 300, 300);
stage.setTitle("Stage");
stage.setScene(scene);
stage.setOnCloseRequest(new EventHandler<WindowEvent>(){
#Override
public void handle(WindowEvent event) {
Platform.exit();
}
});
return stage;
}
});
System.out.println("Stage started");
// how to get rid of this block (or using a countdownlatch) but
// still waiting for the threads to finish?
Set<Thread> threads = Thread.getAllStackTraces().keySet();
if (!fromMain) {
System.out.println("checking threads...");
for (Thread thread : threads) {
if (thread.getName().contains("JavaFX")) {
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
The issue is here that I want to get rid of this nasty block to wait until all the JavaFX platform is explicitly exited.
I appreciate the answer regarding using a countdown latch instead of joining the Java FX thread explicitly. However this still requires me to explictly stop the current thread. However, I would rather like to "tell" JUnit somehow to wait for the JavaFX thread to finish.
So basically what I am looking for is a way to tell JUnit to wait for particular threads without any blocking code inside my test methods.
Appendix: Necessary classes for a minimal running example
public class PlotStage {
public static boolean toolkitInialized = false;
public static void plotStage(QPMApplication stageCreator) {
if (!toolkitInialized) {
Thread appThread = new Thread(new Runnable() {
#Override
public void run() {
Application.launch(InitApp.class);
}
});
appThread.start();
}
while (!toolkitInialized) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Platform.runLater(new Runnable() {
#Override
public void run() {
Stage stage = stageCreator.createStage();
stage.show();
}
});
}
public static class InitApp extends Application {
#Override
public void start(final Stage primaryStage) {
toolkitInialized = true;
}
}
}
public interface QPMApplication {
public abstract Stage createStage();
}
Use a CountDownLatch for that.
Initialize with 1.
When the Stage is closed, invoke countDown().
In the JUnit Test, call await() to wait for the Stage to be closed.
Example:
CountDownLatch cdl = new CountDownLatch(1);
// TODO show the stage and do not forget to add cdl.countDown() to your
// stage.setOnCloseRequest
cdl.await();
Alternative #1:
Use the JavaFX Junit Rule to perform all actions directly on the FX application Thread.
Alternative #2:
Use TestFX, for what I read from your updated description, it fits best.
Related
I am facing one problem in my JavaFx application.
Preface: I don't want to be specific to my application only but want to be generalized so that people like me will get an idea on similar situation.
Background: Implementing a Javafx application using fxml file and multi-threading concept.
Summary: I tried make an application which basically uses multi threading to do some task, and once multi- threading is completed, it will sequentially move to another task. While doing the multi-threading the Main GUI freezes.
What I did,
//This is Main class
Parent Root -> defined on top
public Parent createContent(){
try{
root = FXMLLoader.load(getClass().getResource("Layout.fxml"));
}catch { .....}
}
public void start(){
stage.setScene(new Scene(createContent()));
Task<Void> task = new Task<Void>() {
#Override
public Void call() throws Exception {
Thread.sleep(1000);
return null ;
}
};
task.setOnSucceeded(event->{
stage.show();
});
new Thread(task).run();
}
public static void main(String[] args) {
launch(args);
}
// This is inside the controller on button click event
#FXML
private void start(ActionEvent event) { <---- This one is button click event
Thread t1 = new Thread(new Mul());
t1.start();
Thread t2 = new Thread (new Mul());
t2.start();
}
// Finally
public class Mul implements Runnable {
public void type() {
for (int a = 0; a < 200000; a++) {
System.out.println( Thread.currentThread().getName()+ " says " + a);
}
}
#Override
public void run() {
type();
}
}
Now, here is the outcome.
If I just start the threads from the controller then My main application does not freezes while the thread are running in background. However, since the application runs in a sequence, i.e the next step only works when the threads complete their work
I can use t1.join() and t2.join() , but doing so will freezes my main application(Main application here is the main GUI) and I cannot proceed with it until the threads are completed.
What could be the optimal solution, so that I can use multi threading without blocking the main application or What am I doing wrong here? (info, I came to this solution by following up different suggestions from Stack overflow and google)
Why not do
Task<Void> task = new Task<Void>() {
#Override
public Void call() {
Mul m1 = new Mul();
m1.run();
Mul m2 = new Mul();
m2.run();
return null ;
}
};
new Thread(task).start();
If you really want to "chain" different tasks, call one from the other's onSucceeded handler:
Task<Void> task1 = new Task<Void>() {
#Override
public Void call() {
new Mul().run();
return null ;
}
};
Task <Void> task2 = new Task<Void>() {
#Override
public Void call() {
new Mul().run();
return null ;
}
};
task1.setOnSucceeded(e -> new Thread(task2).start());
new Thread(task1).start();
Obviously this is cleaner if you make Mul a Task subclass instead of a Runnable, and it's better to use an Executor with daemon threads, etc, but this should give you the idea.
I have a class with a method that blocks and would like to validate that it is blocking. The method is as shown below.
public static void main(String[] args) {
// the main routine is only here so I can also run the app from the command line
applicationLauncherInstance.initialize();
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
if (null != application) {
applicationLauncherInstance.terminate();
}
}
});
try {
_latch.await();
} catch (InterruptedException e) {
log.warn(" main : ", e);
}
System.exit(0);
}
How can I write a unit test for such a method. I am stuck before starting.
public class ApplicationLauncherTest extends TestCase {
public void testMain() throws Exception {
ApplicationLauncher launcher = new ApplicationLauncher();
}
}
Thanks to Kulu, I found the solution.
public void testMain() throws Exception {
Thread mainRunner = new Thread(() -> {
ApplicationLauncher.main(new String[]{});
});
mainRunner.start();
Thread.sleep(5000);
assertEquals(Thread.State.WAITING, mainRunner.getState());
mainRunner.interrupt();
}
Bwire's answer is a good way there, but I highly recommend that no
one ever use Thread.sleep() in unit tests for validation of some situation. It's impossible to get the timing right:
If it's too short, you'll get a lotta false results (random failures, yay)
If it's too long, you end up creating painfully slow tests over time. Don't underestimate this.
So, what's the answer? Any time you need to "sleep" to test something, instead "wait" for that to be true (constantly checking). This way:
As soon as the condition is true, your program resumes--no wasted time.
You can set the timeout on this "wait" to a crazy large value, to avoid random failures.
Here's a modified version of Bware's self-response...
public void testMain() throws Exception {
Thread mainRunner = new Thread(() -> {
ApplicationLauncher.main(new String[]{});
});
mainRunner.start();
expectToBlock(mainRunner, 30, TimeUnit.SECONDS);
mainRunner.interrupt();
}
private static void expectToBlock(Thread thread, long waitCount, TimeUnit waitUnits) {
long start = System.currentTimeMillis();
while (System.currentTimeMillis() - start < waitUnits.toMillis(waitCount)) {
if (thread.getState() == Thread.State.WAITING) {
return;
}
Thread.sleep(50); // Don't hog the CPU
}
Assert.fail("Timed out while waiting for thread to block");
}
I am making a simple button game with JavaFX and I need a thread to run so that I can check if an enemy or the player is alive or not. My problem is not starting and using the thread, but stopping it when the window is closed.
I made a sample class to demonstrate what I mean.
private Thread thread;
private boolean running;
private Stage window;
public void run() {
while (running) {
System.out.println("Hello");
}
stopThread();
}
public synchronized void startThread() {
running = true;
thread = new Thread(this, "Monitor");
thread.start();
}
public synchronized void stopThread() {
running = false;
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void start(Stage stage) throws Exception {
window = new Stage();
window = stage;
Pane layout = new Pane();
Scene scene = new Scene(layout);
window.setOnCloseRequest(e -> {
e.consume();
close();
});
window.setScene(scene);
window.show();
}
public void close() {
window.close();
stopThread();
}
public static void main(String[] args) {
Things things = new Things();
things.startThread();
launch(args);
}
When I run it, "Hello" prints continuously, but when I try to close it, the thread keeps running and eclispe goes into debug mode saying:
Thread [JavaFX Application Thread] (Suspended (exception NullPointerException))
QuantumToolkit.runWithoutRenderLock(Supplier<T>) line: not available
GlassWindowEventHandler.handleWindowEvent(Window, long, int) line: not available
WinWindow(Window).handleWindowEvent(long, int) line: not available
WinWindow(Window).notifyClose() line: not available
WinApplication._runLoop(Runnable) line: not available [native method]
WinApplication.lambda$null$145(Runnable) line: not available
2091156596.run() line: not available
Thread.run() line: not available
I have looked around my code and cannot find anything that is null, though.
Assuming Things is the name of the class you showed, you're not stopping the correct thread.
When you call launch(args), the FX Toolkit creates an instance of the application class (which I'm assuming is Things), creates a Stage, and passes the Stage to the application instance's start(...) method (executing that method on the FX Application Thread).
So you create one instance, and start the thread on that instance. Then the FX toolkit creates a second instance, and it's on that instance that you are trying to stop the thread. So you are stopping a different thread to the one you started.
The fix for this is to remove the lines
Things things = new Things();
things.startThread();
from your main(...) method, and just to add
this.startThread();
to the beginning of your start(...) method.
Additionally, as #RyanJ points out, you are deadlocking as you have one thread waiting on a second thread to complete, and both are trying to execute the same synchronized method. Also, you should declare running as volatile, since it is accessed from multiple threads:
private volatile boolean running ;
So this works:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
public class Things extends Application implements Runnable {
private Thread thread;
private volatile boolean running;
private Stage window;
#Override
public void run() {
while (running) {
System.out.println("Hello");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// stopThread();
running = false ;
}
public synchronized void startThread() {
running = true;
thread = new Thread(this, "Monitor");
thread.start();
}
public synchronized void stopThread() {
running = false;
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
#Override
public void start(Stage stage) throws Exception {
startThread();
window = stage;
Pane layout = new Pane();
Scene scene = new Scene(layout);
window.setOnCloseRequest(e -> {
e.consume();
close();
});
window.setScene(scene);
window.show();
}
public void close() {
window.close();
stopThread();
}
public static void main(String[] args) {
launch(args);
}
}
One last point: if this is the only window you have open, the JVM will exit when you close the window, as long as there are no non-daemon threads running. So you can just let the JVM kill your thread by making it a daemon thread. If this works for your real app, you could do any clean-up you needed by overriding the stop method:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
public class Things extends Application implements Runnable {
private Thread thread;
private volatile boolean running;
private Stage window;
#Override
public void run() {
while (running) {
System.out.println("Hello");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// stopThread();
running = false ;
}
public synchronized void startThread() {
running = true;
thread = new Thread(this, "Monitor");
thread.setDaemon(true);
thread.start();
}
#Override
public void start(Stage stage) throws Exception {
startThread();
window = stage;
Pane layout = new Pane();
Scene scene = new Scene(layout);
window.setScene(scene);
window.show();
}
public static void main(String[] args) {
launch(args);
}
}
You're probably hitting a livelock/deadlock situation.
In your run method, after the while loop terminates, you have your thread try to stop itself, and then attempt to wait for itself to die. That's a synchronized method, meaning only one thread can be running it at a time.
When you call it from your main method and try to stop the thread, it will try to join the thread and wait for it to die. Since this first call is already executing your stopThread method, when the while loop terminates in your run method, it will sit there and block, not causing the thread to die. Since the thread doesn't die, the first call to stopThread won't finish.
You could remove stopThread from your run method and it should behave better, though from what you posted here, it looks like a better design might be in order. I'd be curious if my suggestion works.
Upon further inspection, you also have a problem with static/non-static data within your threads.
I'm assuming your Things class implements Runnable, thus when you pass it to the Thread constructor and start it, it gets its own copy of the stack, and it's own local variables. When you call stopThread in your close method, you're not setting the proper running variable (it's not the one the thread running sees). If you make that field static and remove the thread.join... code, it behaves properly.
EDIT:
As a better design choice, it might be wiser to leverage the capability you get with Threads/Runnables and the way they are typically managed in an application (for more info, since you're using JFX, you should look at Services/Tasks)
Split up the thread implementation and the main class, and leverage the function of the thread itself to stop it.
Take this example, which is significantly cleaner, and works just as well:
public class Things implements Runnable {
private volatile boolean running; // this indicates it's running
public Things() {
running = true; // thread is running when it's created (though not really until "run" is called)
}
// called from start()
public void run() {
while (running) {
System.out.println("Hello");
}
}
// call this method to stop the thread, from outside on the object reference
public synchronized void stop() {
running = false;
}
}
In a separate Test/Application class, you can manipulate the Things reference to do what you want, without maintaining a reference to the actual thread.
public class Test extends Application {
private Stage window;
private static Things things;
public void start(Stage stage) throws Exception {
window = new Stage();
window = stage;
Pane layout = new Pane();
Scene scene = new Scene(layout);
window.setOnCloseRequest(new EventHandler<WindowEvent>() {
#Override
public void handle(WindowEvent windowEvent) {
close();
}
});
window.setScene(scene);
window.show();
}
// on close
public void close() {
window.close();
things.stop(); // stop the things object directly
}
public static void main(String[] args) {
things = new Things(); // create new runnable
Thread t = new Thread(things,"Monitor"); // create thread
t.start(); // start thread
launch(args); // launch app
}
}
I have a class which processes something. I'm trying to run a number of instances of this class in parallel.
However, I'm not sure if in TaskManager.startAll(), when I call r.go(), whether this would cause r to start running in its own thread, or within the main thread?
The total execution time that I'm getting seems to be very high, and despite my attempts at optimizing, nothing seems to be having any effect. Also, if I run a profiler on my project in Netbeans, it shows all the threads as sleeping. So I'd like to know if I'm doing something wrong?
This is the structure of the class:
public class TaskRunner implements Runnable {
private boolean isRunning = false;
public void run() {
while(true) {
while (! running) {
try {
Thread.sleep(1);
} catch (Exception e) {
e.printStackTrace();
}
}
process();
}
}
public void go() {
isRunning = true;
}
public void stop() {
isRunning = false;
}
private void process() {
//Do some number crunching and processing here
}
}
Here's how these are being run / managed:
public class TaskManager {
private ArrayList<TaskRunner> runners = new ArrayList<>();
public TaskManager() {
for (int i = 0; i < 10; i++) {
TaskRunner r = new TaskRunner();
new Thread(r).start();
runners.add(r);
}
}
public void startAll() {
for (TaskRunner r : runners) {
r.go();
}
}
}
Indeed, you are not "doing it right." If you want to create a multi-threaded Java application, the place to start is with the java.util.concurrent package.
It appears from your code that you want to run ten tasks in parallel. I assume that after "number crunching and processing," you'll want to aggregate the results and do something with them in the main thread. For this, the invokeAll() method of ExecutorService works well.
First, implement Callable to do the work you show in your process() method.
final class YourTask implements Callable<YourResults> {
private final YourInput input;
YourTask(YourInput input) {
this.input = input;
}
#Override
public YourResults call()
throws Exception
{
/* Do some number crunching and processing here. */
return new YourResults(...);
}
}
Then create your tasks and run them. This would take the place of your main() method:
Collection<Callable<YourResults>> tasks = new List<>(inputs.size());
for (YourInput i : inputs)
tasks.add(new YourTask(i));
ExecutorService workers = Executors.newFixedThreadPool(10);
/* The next call blocks while the worker threads complete all tasks. */
List<Future<YourResult>> results = workers.invokeAll(tasks);
workers.shutdown();
for (Future<YourResult> f : results) {
YourResult r = f.get();
/* Do whatever it is you do with the results. */
...
}
However, I'm not sure if in TaskManager.startAll(), when I call r.go(), whether this would cause r to start running in its own thread, or within the main thread?
So my first comment is that you should make isRunning be volatile since it is being shared between threads. If the threads are not starting when it goes to true (or seem to be delayed in starting) then I suspect that's your problem. volatile provides memory synchronization between the threads so the thread that calls go() and makes a change to isRunning will be seen immediately by the thread waiting for the change.
Instead of spinning like this, I would use wait/notify:
// this synchronizes on the instance of `TaskRunner`
synchronized (this) {
// always do your wait in a while loop to protect against spurious wakeups
while (!isRunning && !Thread.currentThread().isInterrupted()) {
try {
// wait until the notify is called on this object
this.wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
e.printStackTrace();
}
}
Then in the go() method you should do the following. stop() would be similar.
public void go() {
synchronized (this) {
isRunning = true;
this.notifyAll();
}
}
Notice that you should handle thread interrupts carefully. Test for isInterrupted() in the while running loop and re-interrupt a thread when InterruptedException is thrown is always a good pattern.
The total execution time that I'm getting seems to be very high, and despite my attempts at optimizing, nothing seems to be having any effect. Also, if I run a profiler on my project in Netbeans, it shows all the threads as sleeping.
So although the threads are mostly sleeping, they are still each looping 1000 times a second because of your Thread.sleep(1). If you increased the time sleeping (after making isRunning be volatile) they would loop less but the right mechanism is to use the wait/notify to signal the thread.
Awful solution, terrible. first I highly recommend you start reading some tutorial like [this]
Second, if threads should wait for a signal to go for some job, so why just don't you wait them!!!!!, something like this
import java.util.ArrayList;
public class TaskManager
{
//////////////////////
public volatile static Signal wait=new Signal();
//////////////////////
private ArrayList<TaskRunner> runners = new ArrayList<>();
public TaskManager()
{
for (int i = 0; i < 10; i++)
{
TaskRunner r = new TaskRunner();
new Thread(r).start();
runners.add(r);
}
try {
Thread.sleep(1000);
startAll();
Thread.sleep(1000);
pauseAll();
Thread.sleep(1000);
startAll();
Thread.sleep(1000);
haltAll();System.out.println("DONE!");
}catch(Exception ex){}
}
public void startAll()
{
synchronized(wait){
wait.setRun(true);;
wait.notifyAll();
}
}
public void pauseAll(){
wait.setRun(false);
}
public void haltAll(){
for(TaskRunner tx:runners){tx.halt();}
}
public static void main(String[] args) {
new TaskManager();
}
}
class TaskRunner implements Runnable
{
private Thread thisThread;
private volatile boolean run=true;
public void run()
{
thisThread=Thread.currentThread();
while(run){
if(!TaskManager.wait.isRun()){
synchronized(TaskManager.wait)
{
if(!TaskManager.wait.isRun()){
System.out.println("Wait!...");
try
{
TaskManager.wait.wait();
}
catch (Exception e)
{
e.printStackTrace();
break;
}
}
}}
process();
}
}
private double r=Math.random();
private void process(){System.out.println(r);try {
Thread.sleep(10);
} catch (Exception e) {
// TODO: handle exception
}}
public void halt(){run=false;thisThread.interrupt();}
}
class Signal{
private boolean run=false;
public boolean isRun() {
return run;
}
public void setRun(boolean run) {
this.run = run;
}
}
in above sample, all runners works till the Signal run boolean is true, and simple TaskManager class set tit as false for every time it needs to pause the threads. and about the halt, it just set the shutdown(run) flag to false, and also interrupt the thread because of if thread is in wait state.
I hope I could prove your solution is like dream-on story, and also could explained enough about my solution.
have a good parallel application :)
Hi i got following problem...
I have main jframe started like this:
public static void main (String args[]){
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
Form3 myF=new Form3();
}
});
};
in the jframe i have Jpanels. On jpanel i want to start 2nd thread.
I tried it like this:
try {
while (DBAccess.haveResult("ASS"+harnessId)==null&&cancelCycle == 0) {
thread1.sleep(3*1000);
System.out.println("+++++++++");
System.out.println(DBAccess.haveResult("ASS"+harnessId));
res = DBAccess.haveResult("ASS"+harnessId);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
but I am unable to stop that thread and cant even cancel it, because main window stops reacting
to clarify my problem:
i have "Test" button on JPanel, which is starting test process. Test process consists of loop whiuch is repeating every 3 seconds, this loop checks database status. Problem is I am unable to stop this loop until the status appears in db (while condition), because window is busy after i click on "test". Even implementing runnable and putting test method into "run()" doesnt worked.
testbutton source code:
if (e.getActionCommand().equals("Test")){
run();}
run method:
#Override
public final void run() {
test();
}
test method:
Map result_row = DBAccess.addRow("ASS"+harnessId,htOperList.get(seqNumber-1).getNametestprogram(),"",null);
if(result_row.containsKey("ADDROW")){System.out.println("Record inserted" );}
Database db = null;
Map res = null;
try {
while (DBAccess.haveResult("ASS"+harnessId)==null&&cancelCycle == 0) {
thread1.sleep(3*1000);
System.out.println(DBAccess.haveResult("ASS"+harnessId));
res = DBAccess.haveResult("ASS"+harnessId);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
You are blocking the event dispatch thread. Use a SwingWorker for heavy tasks. Put the main DB operation in doInBackround(), and use publish() for the interim results.
If you need to stop it before doInBackround() completes, you can use cancel(). See here for notes about that.