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.
Related
I don't know if there are any other good ways to achieve the results I want, thank you.
I have a requirement, according to the URL, create multiple webview threads, and execute them in order, such as thread execution, then trigger thread two execution, and so on, I use the synchronized (lobject) method, but in JAVAfx encountered a problem, the code is as follows:
public class LockObject {
public int orderNum = 1;
public final static int MaxValue=9;
public LockObject(int orderNum){
this.orderNum = orderNum;
}
}
public class DownloadThread extends Thread{
private LockObject lobject;
private int printNum =0;
private String url;
public DownloadThread(LockObject lobject,int printNum,String url){
this.lobject=lobject;
this.printNum = printNum;
this.url = url;
}
#Override
public void run() {
synchronized(lobject){
while(lobject.orderNum <= lobject.MaxValue){
if(lobject.orderNum == printNum){
System.out.print(printNum);
Platform.runLater(new Runnable() {
#Override
public void run() {
webView.getEngine().load(url);
webView.getEngine().getLoadWorker().stateProperty().addListener(new ChangeListener<Worker.State>() {
#Override
public void changed(ObservableValue<? extends Worker.State> observable, Worker.State oldValue, Worker.State newValue) {
if (newValue == Worker.State.SUCCEEDED) {
try {
//xxxxx
// java.lang.IllegalMonitorStateException
lobject.notifyAll();
} catch (Exception e) {
e.printStackTrace();
}
}
}
});
}
});
lobject.orderNum++;
if(lobject.orderNum==downloadThreads.length){
saveCsvFile(goodCSVS);
}
//lobject.notifyAll(); is ok
}else{
try {
lobject.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
Place of call
private DownloadThread[] downloadThreads;
LockObject lobject = new LockObject(1);
downloadThreads = new DownloadThread[tableView.getItems().size()];
for (int i = 0; i < tableView.getItems().size(); i++) {
UrlModel item = tableView.getItems().get(i);
downloadThreads[i] = new DownloadThread(lobject,tableView.getItems().size()-i,item.getLink());
downloadThreads[i].start();
}
Calling lobject.notifyAll() in the run method in Platform.runLater will report an IllegalMonitorStateException. After the address is processed, I want to wake up the next thread to execute.
If you need to execute multiple tasks in order, there's no need to create multiple threads. Just using a single thread will guarantee the next task only executes after the previous one has completed. You should also consider using a CountDownLatch instead of synchronizing on an object.
ExecutorService executor = Executors.newSingleThreadExecutor();
try {
for (UrlModel model : tableView.getItems()) {
executor.submit(() -> {
CountDownLatch latch = new CountDownLatch(1);
Platform.runLater(() -> {
engine.load(model.getLink())
engine.getLoadWorker().runningProperty().addListener((obs, ov, nv) -> {
if (!nv) {
latch.countDown();
}
});
});
latch.await();
// do whatever needs to happen after the WebEngine finishes loading
return null; // using #submit(Callable) and Callable needs to return something
});
}
} finally {
executor.shutdown();
}
Some notes:
You may want to avoid creating the ExecutorService if the table has no items to process. That is, assuming you don't reuse the same ExecutorService every time.
If you reuse the ExecutorService, don't call shutdown().
This ExecutorService uses non-daemon threads. You can customize this by supplying a ThreadFactory that creates daemon threads.
I added a listener to the Worker#running property instead of the status property to make it easier to ensure countDown() is invoked no matter the terminal status of the load (i.e. whether it's SUCCEEDED, CANCELLED or FAILED).
You may want to remove the the listener added to the Worker's property when it's finished. You can do this by using an anonymous class (rather than the lambda expression I used) and calling obs.removeListener(this) inside the changed method, where obs is the ObservableValue argument.
I have a Task which should be runnable and updateable on Console and GUI. Consider my Task written as
public static Task<Void> doStuff() {
Task<Void> task;
task = new Task<Void>() {
final int totalSteps = 4;
#Override
public Void call() throws Exception {
updateProgress(0, totalSteps);
updateMessage("1");
action(1);
updateProgress(0, totalSteps);
updateMessage("2");
action(2);
//etc..
return null;
}
};
new Thread(task)
.start();
return task;
}
With bonding the Progress and Message Property within my JavaFX GUI, everything works as expected and the GUI gets updated according to the Progress.
Within my CLI, I tried to build a simple Progress Bar which updates the User about the Operation Progress
private static void progressBar(Task task) {
task.progressProperty().addListener((new ChangeListener() {
#Override
public void changed(ObservableValue observable, Object oldValue, Object newValue) {
// Return to line beginning
System.out.print("\r");
int percentage = (int) (100 * task.progressProperty().get());
System.out.format("[%3d%%] %s", percentage, task.messageProperty().get());
if (percentage == 100) {
System.out.println("Finished");
}
}
}));
}
}
As far as I could see with debugging, the Change Listeners changed Method will not get triggered. What did I set up wrong about it? Even the Finished Print at the End will not get written.
As stated in the comments, updates to the properties in a JavaFX Task are performed on the FX Application Thread. That thread is the thread used to render the JavaFX Scene graph and is started by the JavaFX toolkit when it is launched. If the JavaFX toolkit is not running, then the thread won't be started and those properties will not be updated.
If you want something that can be run in a background that needs to be functional outside of a JavaFX application, then you should use threading facilities that are not dependent on JavaFX. In this case you can simply implement Runnable or Callable. If you want to provide notifications when state changes, create a callback, to be called when the state changes. Callbacks are best represented using interfaces from the java.util.function package.
In the case you show, it looks like you only really need the message and progress together, so you could probably use a BiConsumer<String, Integer>.
public class DoStuff implements Runnable {
private final int totalSteps ;
private BiConsumer<String, Integer> update ;
public DoStuff(int totalSteps) {
this.totalSteps = totalSteps ;
}
public void setUpdate(BiConsumer<String Integer> update) {
this.update = update ;
}
#Override
public void run() {
if (update != null) {
update.accept("0", 0) ;
}
for (int i = 1 ; i <= totalSteps ; i++) {
action(i);
if (update != null) {
update.accept(Integer.toString(i), i);
}
}
}
private void action(int i) {
// ...
}
public int getTotalSteps() {
return totalSteps() ;
}
}
and now you would do
public void progressBar(DoStuff doStuff) {
doStuff.setUpdate((s, p) -> {
// Return to line beginning
System.out.print("\r");
int percentage = 100 * p / doStuff.getTotalSteps();
System.out.format("[%3d%%] %s", percentage, s);
if (percentage == 100) {
System.out.println("Finished");
}
});
}
And you execute this in a background thread with
new Thread(doStuff).start();
If you wanted to use this in a JavaFX environment, you can, but make sure your callback updates any UI components on the FX Application Thread:
DoStuff doStuff = ... ;
doStuff.setUpdate((s, p) -> Platform.runLater(() -> {
label.setText(s);
double progress = 1.0 * p / doStuff.getTotalSteps();
progressBar.setProgress(p);
}));
It's also reasonably easy to create a Task<Void> that wraps this, and exposes the progress and message in the usual JavaFX way:
DoStuff doStuff = ... ;
Task<Void> doStuffTask = new Task<Void>() {
#Override
protected Void call() {
doStuff.setUpdate((s, p) -> {
updateProgress(p, doStuff.getTotalSteps());
updateMessage(s);
});
doStuff.run();
return null ;
}
};
Then do
progressBar.progressProperty().bind(doStuffTask.progressProperty());
label.textProperty().bind(doStuffTask.messageProperty());
Thread t = new Thread(doStuffTask);
t.setDaemon(true);
t.start();
as usual.
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.
For performance reason I would like to use a forEach loop of a parallel Lambda stream in order to process an instance of a Collection in Java. As this runs in a background Service I would like to use the updateProgress(double,double) method in order to inform the user about the current progress.
In order to indicate the current progress I need a certain progress indicator in form of a Integer counter. However, this is not possible as I can only access final variables within the Lambda expression.
Code example see below, Collection is only a place holder for any possible instance of a Collection:
int progress = 0;
Collection.parallelStream().forEach(signer -> {
progress++;
updateProgress(progress, Collection.size());
});
I'm aware that I can solve this problem by using a simple for-loop. However, for performance reason it would nice to solve it in this way.
Does anybody know a more or less neat solution to this?
As proposed by markspace, using an AtomicInteger is a good solution:
AtomicInteger progress = new AtomicInteger();
Collection.parallelStream().forEach(signer -> {
progress.incrementAndGet();
// do some other useful work
});
I would not use the runLater() variant as your goal is a high performance, and if many parallel threads will generte JavaFX 'runLater' tasks, you will again create a bottleneck...
For the same reason I would NOT call an update to the ProgressBar each time, but use a seaparte JavaFX Timeline to update the progress bar in regular intervals independently from the processing threads.
Here is a full code comparing sequential and parallel processing with ProgressBar. If you remove the sleep(1) and set the number of items to 10 million it will still work concurrently and efficiently...
public class ParallelProgress extends Application {
static class ParallelProgressBar extends ProgressBar {
AtomicInteger myDoneCount = new AtomicInteger();
int myTotalCount;
Timeline myWhatcher = new Timeline(new KeyFrame(Duration.millis(10), e -> update()));
public void update() {
setProgress(1.0*myDoneCount.get()/myTotalCount);
if (myDoneCount.get() >= myTotalCount) {
myWhatcher.stop();
myTotalCount = 0;
}
}
public boolean isRunning() { return myTotalCount > 0; }
public void start(int totalCount) {
myDoneCount.set(0);
myTotalCount = totalCount;
setProgress(0.0);
myWhatcher.setCycleCount(Timeline.INDEFINITE);
myWhatcher.play();
}
public void add(int n) {
myDoneCount.addAndGet(n);
}
}
HBox testParallel(HBox box) {
ArrayList<String> myTexts = new ArrayList<String>();
for (int i = 1; i < 10000; i++) {
myTexts.add("At "+System.nanoTime()+" ns");
}
Button runp = new Button("parallel");
Button runs = new Button("sequential");
ParallelProgressBar progress = new ParallelProgressBar();
Label result = new Label("-");
runp.setOnAction(e -> {
if (progress.isRunning()) return;
result.setText("...");
progress.start(myTexts.size());
new Thread() {
public void run() {
long ms = System.currentTimeMillis();
myTexts.parallelStream().forEach(text -> {
progress.add(1);
try { Thread.sleep(1);} catch (Exception e1) { }
});
Platform.runLater(() -> result.setText(""+(System.currentTimeMillis()-ms)+" ms"));
}
}.start();
});
runs.setOnAction(e -> {
if (progress.isRunning()) return;
result.setText("...");
progress.start(myTexts.size());
new Thread() {
public void run() {
final long ms = System.currentTimeMillis();
myTexts.forEach(text -> {
progress.add(1);
try { Thread.sleep(1);} catch (Exception e1) { }
});
Platform.runLater(() -> result.setText(""+(System.currentTimeMillis()-ms)+" ms"));
}
}.start();
});
box.getChildren().addAll(runp, runs, progress, result);
return box;
}
#Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setTitle("ProgressBar's");
HBox box = new HBox();
Scene scene = new Scene(box,400,80,Color.WHITE);
primaryStage.setScene(scene);
testParallel(box);
primaryStage.show();
}
public static void main(String[] args) { launch(args); }
}
The naive solution would be to have progress as a field of some surrounding object; then referring to progress from a lambda closure would actually mean this.progress, where this is final, thus the compiler would not complain. However, the resulting code would access the progress field from multiple threads concurrently, which could cause race conditions. I suggest restricting access to the progress field to the JavaFX application thread, by using Platform.runLater. The whole solution then looks like this:
// accessed only on JavaFX application thread
private int progress = 0;
// invoked only on the JavaFX application thread
private void increaseProgress() {
progress++;
updateProgress(progress, collection.size());
}
private void processCollection() {
collection.parallelStream().forEach(signer -> {
// do the work (on any thread)
// ...
// when done, update progress on the JavaFX thread
Platfrom.runLater(this::increaseProgress);
});
}
I have 6 functions which I need to run in specific time intervals:
public void runFirst() {
System.out.println("First method");
}
public void runSecond() {
System.out.println("Second method");
}
public void runThird() {
System.out.println("Third method");
}
public void runFourth() {
System.out.println("Fourth method");
}
public void runFifth() {
System.out.println("Fifth method");
}
public void runSixth() {
System.out.println("Sixth method");
}
I need to run "first" as soon as i click the button, second must be after 65 seconds, third 20 seconds after second, fourth 15 seconds after the third one and so on, at the time i'm using Thread.sleep but i will need to make it without sleeps.
What is the best way and can someone show me some example based on my methods.
you can use Quartz. While clicking the button you can get system current time and add a new scheduled job to run on specific date&time. So Quartz will handle it to run on the time.
Another way is to create a new Thread and define on it the sleep period of time and let that to run function.
Why cant you use
Thread.sleep
and run this code in different thread (then, the whole app wont stop on sleep)
Maybe you want to check the #wait(timeout) method, the one with timeout.
Quote:
"... the thread lies dormant until the specified amount of real time
has elapsed..."
To run a task after some time, you should use a Timer, which is a "A facility for threads to schedule tasks for future execution in a background thread. ".
It frees you from creating your own thread : less error-prone and easier. It can manage several scheduled tasks. Beware though, these task should be short-lived (other they will block the thread used for scheduling puropose by the timer)..
Use a ExecutorService. The basic idea would be something like this:
// "Global" resource
final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(5); // Adjust threadpool size
...
// inside onclick() processing
ScheduledFuture<Void> future1 = executorService.schedule(new Callable<Void>() {
#Override Void call() {
try {
runFirst();
} finally {
scheduleFuture2();
}
}
},
65,
TimeUnit.SECONDS);
...
void scheduleFuture2() {
ScheduledFuture<Void> future2 = executorService.schedule(new Callable<Void>() {
#Override Void call() {
try {
runSecond();
} finally {
scheduleFuture3();
}
}
},
20,
TimeUnit.SECONDS);
}
...
void scheduleFuture3() {
ScheduledFuture<Void> future3 = executorService.schedule(new Callable<Void>() {
#Override Void call() {
try {
runThird();
} finally {
scheduleFuture4();
}
}
},
15,
TimeUnit.SECONDS);
}
...
// And so on
Some notes:
if runFirst() , runSecond(), ... perform Swing / AWT UI operations, the you should proably make use of SwingUtilities.invokeLater inside those methods
don't forget to invoke executorService.shutdown() when you not going to use this mechanism anymore. If you forget about it, you will "leak" threads.
The references to Void above (uppercase "V") are intentional: we are using the Void class and not the void type
Use a ScheduledExecutorService!
{
ScheduledExecutorService worker = Executors.newScheduledThreadPool(1);
worker.execute(() -> runFirst());
worker.schedule(() -> runSecond(), 65, TimeUnit.SECONDS);
worker.schedule(() -> runThird(), 85, TimeUnit.SECONDS);
worker.schedule(() -> runFourth(), 100, TimeUnit.SECONDS);
worker.schedule(() -> runFifth(), 110, TimeUnit.SECONDS);
worker.schedule(() -> runSixth(), 115, TimeUnit.SECONDS);
worker.shutdown();
}
If you cannot use Java 8 for some reason, use anonymous implementations of Runnable instead of Lambda expressions:
// worker.schedule(() -> runSixth(), 115, TimeUnit.SECONDS);
worker.schedule(new Runnable(){
#Override
public void run() {
runSixth();
}}, 115, TimeUnit.SECONDS);
Create a Thread class and another Class for your methods
Now:
public class ThreadTest implements Runnable {
private int functionNumber;
private int time2start;
private YourClass obj;
public ThreadTest(int functionNumber, int time2start, YourClass obj) {
this.functionNumber = functionNumber;
this.time2start = time2start;
this.obj = obj;
}
public void run() {
try {
Thread.currentThread().sleep(time2start);
} catch (Exception ex) {
}//Time Delay before executing methods
switch (functionNumber) {
case 1:
obj.runFirst();
break;
case 2:
obj.runSecond();
break;
case 3:
obj.runThird();
break;
case 4:
obj.runFourth();
break;
//keep adding
}
}
}
then Class for your methods :
public class YourClass {
public void runFirst() {
System.out.println("First method");
}
public void runSecond() {
System.out.println("Second method");
}
public void runThird() {
System.out.println("Third method");
}
public void runFourth() {
System.out.println("Fourth method");
}
public void runFifth() {
System.out.println("Fifth method");
}
public void runSixth() {
System.out.println("Sixth method");
}
}
Now this is the method for onClick event for the button:
//on button click
ThreadTest th1 = new ThreadTest(1, 0, obj);//here obj is YourClass
ThreadTest th2 = new ThreadTest(2, 65000, obj);//65 SECONDS
//... keep adding
Thread thread1 = new Thread(th1);
Thread thread2 = new Thread(th2);
//...keep adding
thread1.start();
thread2.start();
//...keep adding