I have a simple thread like this.
public class CameraThread extends Thread {
private AtomicBoolean runCamera;
public CameraThread(AtomicBoolean runCamera) {
this.runCamera = runCamera;
}
#Override
public void run() {
while (Main.RUNTHREAD) {
while (runCamera.get()) {
Platform.runLater(() -> {
System.out.println("Hello");
threadSleep();
});
}
}
}
private void threadSleep() {
try {
Thread.sleep(2000L);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
And when I set runCamera to runCamera.set(true) utside from the thread, the whole GUI freezes and I cannot do anything.
This is a minimal example and I can't get it to work properly.
I have used RunLater command before, but this time, I'm sitting at a Dell precision M6400 machine from 2007. Could it happen that this machine cannot handle threads with Java?
Or how can I solve this issue?
To reproduce this issue, just type the following:
wget https://github.com/DanielMartensson/Darknet-Data-Creator/archive/main.zip
unzip Darknet-Data-Creator-main.zip
cd Darknet-Data-Creator-main
mvn javafx:run
Then click on Scan button, select a web camera (USB, laptop camera) and then press Save to folder button. Just select some arbitary folder. Then press Open camera button
The issue is that you are using Thread.Sleep() inside Platform.runLater(...), which means that you are sleeping the GUI, not your camera thread.
Try this instead, note how runLater is outside of the Platform.runLater code:
#Override
public void run() {
while (Main.RUNTHREAD) {
while (runCamera.get()) {
Platform.runLater(() -> {
System.out.println("Hello");
});
//Now thread sleep is outside of runLater:
threadSleep();
}
}
}
The only thing that should go inside the runlater is things that directly change the GUI. Any calculation, sleeping, processing, file reading etc should be kept separate.
Related
I write Java SE 8 desktop application. It's got a Swing UI.
Platform:
Eclipse IDE
Windows 10 OS
Now when I close the main window, by pressing on the "X" on the top-right-corner, I have a listener to listen for such event.
The listener right here:
private void listenerForClosingResources(){
this.addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent e) {
if(e.getID() == WindowEvent.WINDOW_CLOSING){
CountDownLatch continueOn = new CountDownLatch(1);
saveUnsavedTmpProject(continueOn);
try {
continueOn.await();
}
catch(InterruptedException ee) {
ee.printStackTrace();
}
}
}
});
}
So, I use the listener to identify the window closing event, and when that happens I ask the user whether or not to save the project (it's data on DB).
This method (saveUnsavedTmpProject(continueOn);) leads to the other window which supposed to take the name under which to save the project.
Now the CountDownLatch forces the main window to stay up, up till when the user confirms/rejects saving the project on the other panel.
The other class method which creates the window, leading to saving the project, is right here:
public static void getInstance(CountDownLatch continueOn, String openProjectName) {
if(frame == null) {
synchronized(SaveAsPane.class) {
if(frame == null) {
carryOn = continueOn;
if(!openProjectName.isEmpty()){
openProject = openProjectName;
}
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
frame = new SaveAsPane();
frame.setVisible(true);
frame.setLocationRelativeTo(MainGUI.getMainGUI());
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
}
}
Now, when I run the app, I don't get inside the run() method (and no window pops-up). But that only happens when I access this method only from the mentioned above listener. Which has the CountDownLatch, and it appears that it stops the execution of the new thread.
The latch gets counted-down when the user confirms/denies saving the project, so that the execution flow continues on.
Yet, I create the additional thread on the EventQueue.
How come that the thread gets stopped?
The Java group on facebook.com pointed me to the right direction.
The solution is this:
redefine what the close button (X) does on the main GUI.
And here it comes:
setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
And now when I click the main GUI window's close button, the close does not lead to closing the window. Meaning that I don't need any longer the CountDownLatch class, which was stopping the main window from closing up (and waiting till the user counts-down on the other class).
In the end, I made the app to work in the way I like.
This is my first time trying to use Swing components for a GUI, I am trying to implement a solution that allows a user to run 2 asynchronous remote commands.
The two commands in a nutshell are :
execute command on remote server
download data
My problem is that though I've employed a SwingWorker, my main menu still freezes. Moreover, the SwingWorker is passed through and the second command is execute prior to the first command being added.
I've gone through many, many examples and explanations online, and I feel like I'm still missing some crucial intuition that would allow me to make this work.
What is the problem with my swing worker, in that it will still freeze the GUI and isn't waiting until after completion to do the rest of the code?
Edit: Ultimately I want to also create a progress bar, which shows the amount of time left in the task before completion.
GUI Class - Basic GUI with Buttons
public TestGUI(){
//code to show Gui with buttons
//code also contains mouse listener:
btn.addMouseListener(new MouseAdapter() { // listener
#Override
public void mousePressed(MouseEvent e){
SampleClass.doRemoteTask();
}
});
}
Sample Class - Run Remote Command using Swing Worker in Background
public SampleClass(){
public static void doRemoteTask(){
//create sample worker
final SampleWorker sampleworker = new SampleWorker(command, session);
//add change listener to wait for state change.
sampleworker.addPropertyChangeListener(new PropertyChangeListener(){
#Override
public void propertyChange(PropertyChangeEvent event) {
if(StateValue.DONE == sampleworker.getState()){
try {
Integer i = sampleworker.get();
} catch (InterruptedException | ExecutionException e) {
System.out.println("Could not get");
e.printStackTrace();
}
};
}
});
//do other stuff after the state DONE
sampleworker.execute(); //sample worker is a long task. This is why it was created in the Swing Worker.
}
}
Sample Worker Class - Run Command in Background
protected Integer doInBackground() throws Exception {
byte[] tmp=new byte[1024];
int j = 0;
publish("Start");
while(true){
//do stuff
if(j % 100 == 0){
setProgress(j);
}
//write to System.out then exit
break;
}
try{Thread.sleep(1000);}catch(Exception ee){}
}
publish("Completed");
return j;
}
My while(true) is only running once, so I'm trying to add breakpoints to see what's going on, but they never seem to be reached within my run(). I'm using IntelliJ. In the debugger there's a "Threads" tab. Do I need to do something in that tab like select the right thread in order for my breakpoint to be reached? I also see thread names and am wondering how I can find the right thread in this list.
public class MyClass extends ServerWorkflowProcess<OtherClass> {
private ExecutorService executorService = Executors.newSingleThreadExecutor();
...
#Override
public void bootup() {
logger.info("Booting up: " + this);
BackgroundProcess backgroundImpositioner = new BackgroundProcess(this.getCollection());
executorService.submit(backgroundImpositioner);
}
#Override
public void shutdown() {
executorService.shutdown();
}
}
Background process
public class BackgroundProcess implements Runnable {
protected volatile Logger logger = Logger.getLogger(BackgroundImpositioner.class.getName());
Collection<ImpositionWorkstation> impositionWorkstations;
public BackgroundImpositioner(Collection<ImpositionWorkstation> impositionWorkstation) {
this.impositionWorkstations = impositionWorkstation;
}
public void run() {
while(true) {
logger.info("looping");
for (ImpositionWorkstation workstation : impositionWorkstations) {
if (workstation.canAcceptWork()) {
//go do work in another thread so we're not blocking this
workstation.getWorkFromQueue();
try {
workstation.doWork();
} catch (ImpositionException e) {
logger.severe(e.getMessage());
}
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
logger.severe("Background impositioner was interrupted");
}
}
}
}
Side note: the console shows "looping", so I know it gets executed once. The breakpoint never gets hit and it doesn't execute more than once.
It happened to me once that i couldn't make Intellij Idea stop in breakpoints. Basically the problem is that once a thread is stopped in a breakpoint the others won't stop.
There is a setting in the breakpoints properties dialog that prevents this.
Right click on a breakpoint and select 'View Breakpoints'.
On the dialog select a breakpoint.
You will notice on the right of suspend checkbox 2 radio buttons: All and Thread. Select All. Aditionally you can make that the default (Make Default button on the right). The default value will be used for any new breakpoints you add. The old ones need to be changed manually.
EDIT
Additional info on the Intellij help site: Breakpoint options
Don’t let exceptions slip through silently. Use the Future returned by the submit method.
Future<?> f=executorService.submit(backgroundImpositioner);
try {
f.get();
} catch(Exception ex) {
ex.printStackTrace();
}
Then you know more.
The code above is just for finding your actual problem. For production environments you wouldn’t wait for completion but rather log the exception when it occurred, e.g.:
executorService.execute(new FutureTask<Object>(backgroundImpositioner, null)
{
#Override
protected void done() {
if(!isCancelled()) try {
get();
} catch(InterruptedException ex) {
throw new AssertionError("on completed task", ex);
} catch(ExecutionException ex) {
logger.log(Level.SEVERE, "in background task", ex.getCause());
}
}
});
For a reason beyond me, I was not able to breakpoint the while(true) line, but was able to drop breakpoints elsewhere within the run().
If there's no exception thrown inside the run method, i can only assume that one of the calls never returns.
Can you put output statements after every single call to see how far you get?
I guess either workstation.canAcceptWork() or workstation.doWork() is the culprit.
I've met a similar problem that IntelliJ never hits my breakpoint in the run() method of a Runnable class. I found that the only position for the breakpoint to be hit is at the line of public void run() {.
I have the following thread which simply prints a dot every 200ms:
public class Progress {
private static boolean threadCanRun = true;
private static Thread progressThread = new Thread(new Runnable()
{
public void run() {
while (threadCanRun) {
System.out.print('.');
System.out.flush();
try {
progressThread.sleep(200);
} catch (InterruptedException ex) {}
}
}
});
public static void stop()
{
threadCanRun = false;
progressThread.interrupt();
}
public static void start()
{
if (!progressThread.isAlive())
{
progressThread.start();
} else
{
threadCanRun = true;
}
}
}
I start the thread with this code (for now):
System.out.println("Working.");
Progress.start();
try {
Thread.sleep(10000); //To be replaced with code that does work.
} catch (InterruptedException ex) {}
Progress.stop();
What's really strange is this:
If I use System.out.println('.'); , the code works exactly as expected. (Apart from the fact that I don't want a new line each time).
With System.out.print('.');, the code waits for ten seconds, and then shows the output.
System.out.println:
Print dot, wait 200ms, print dot, wait 200ms etc...
System.out.print:
Wait 5000ms, Print all dots
What is happening, and what can I do to go around this behaviour?
EDIT:
I have also tried this:
private static synchronized void printDot()
{
System.err.print('.');
}
and printDot() instead of System.out.print('.');
It still doesn't work.
EDIT2:
Interesting. This code works as expected:
System.out.print('.');
System.out.flush(); //Makes no difference with or without
System.out.println();
This doesn't:
System.err.print('.');
System.err.flush();
System.out.print('.');
System.out.flush();
Solution: The issue was netbeans related. It worked fine when I run it as a jar file from java -jar.
This is one of the most frustrating errors I have seen in my life. When I try to run this code with breakpoints in debug mode, everything works correctly.
The stdout is line buffered.
Use stderr, or flush the PrintStream after each print.
(This is weird code -- there are much cleaner ways to write and manage threads. But, that's not the issue.)
Your IDE must be buffering by line. Try running it directly on the command line. (And hope that the shell isn't buffering either, but shouldn't.)
The println method automatically flushes the output buffer, the print method not. If you want to see the output immediately, a call to System.out.flush might help.
I think this is because the println() method is synchronized
(This is not an answer; the asker, David, requested that I follow up on a secondary point about rewriting the threading. I am only able to post code this way.)
public class Progress {
private ProgressRunnable progressRunnable = new ProgressRunnable();
public void start() {
new Thread(progressRunnable).start();
}
public void stop() {
progressRunnable.stop();
}
private class ProgressRunnable implements Runnable {
private final AtomicBoolean running = new AtomicBoolean(true);
#Override
public void run() {
while (running.get()) {
System.out.print('.');
System.out.flush();
try {
Thread.sleep(200);
} catch (InterruptedException e) {
}
}
}
private void stop() {
running.set(false);
}
}
public static void main(String[] args) {
Progress progress = new Progress();
progress.start();
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
}
progress.stop();
}
}
I tested your code, with System.out.print() and System.out.flush(). The code works for me, except for the code:
while (!threadCanRun)
{
Thread.yield();
}
in Progress class. Doing that, the thread is pausing allowing other thread to execute, as you can see in the thread api page. Removing this part, the code works.
But I don't understand why do you need the yield method. If you call Progress.stop(), this will cause to invoke the yield method. After the thread will stop with interrupt, (after waiting a huge amount of time on my pc).
If you want to allow other threads executing and the current thread pausing, consider the join() method.
If you want to stop the current thread, maybe you can consider to remove the
while(!threadCanRun) loop, or place Thread.currentThread().join() before Thread.interrupt() in the stop() method to wait for the completion of other threads, or simply call the p.stop() method .
Take a look to these posts.
First off I've been working with Java's Concurrency package quite a bit lately but I have found an issue that I am stuck on. I want to have and Application and the Application can have a SplashScreen with a status bar and the loading of other data. So I decided to use SwingUtilities.invokeAndWait( call the splash component here ). The SplashScreen then appears with a JProgressBar and runs a group of threads. But I can't seem to get a good handle on things. I've looked over SwingWorker and tried using it for this purpose but the thread just returns. Here is a bit of pseudo code. and the points I'm trying to achieve.
Have an Application that has a SplashScreen that pauses while loading info
Be able to run multiple threads under the SplashScreen
Have the progress bar of the SplashScreen Update-able yet not exit until all threads are done.
Launching splash screen
try {
SwingUtilities.invokeAndWait( SplashScreen );
} catch (InterruptedException e) {
} catch (InvocationTargetException e) { }
Splash screen construction
SplashScreen extends JFrame implements Runnable{
public void run() {
//run threads
//while updating status bar
}
}
I have tried many things including SwingWorkers, Threads using CountDownLatch's, and others. The CountDownLatch's actually worked in the manner I wanted to do the processing but I was unable to update the GUI. When using the SwingWorkers either the invokeAndWait was basically nullified (which is their purpose) or it wouldn't update the GUI still even when using a PropertyChangedListener. If someone else has a couple ideas it would be great to hear them. Thanks in advance.
I actually got ready to post better code to help out and found my solution. I thank you for all who helped.
For running a series of operations in the background and reporting progress, use SwingWorker.
The background method does the background processing.
Use the publish method to post periodic status updates.
Override the process method to handle the updates (process always executes on the EDT).
progressBar = new JProgressBar();
sw = new SwingWorker<Boolean,Integer>() {
protected Boolean doInBackground() throws Exception {
// If any of the operations fail, return false to notify done()
// Do thing 1
publish(25); // 25% done
// Do thing 2
publish(50); // 50% done
// Do thing 3
publish(75); // 75% done
// Do thing 4
return true;
}
protected void process(List<Integer> chunks) {
for (Integer i : chunks)
progressBar.setValue(i);
}
protected void done() {
try {
boolean b = get();
if (b)
progressBar.setValue(100); // 100% done
else
// Notify the user processing failed
}
catch (InterruptedException ex) {
// Notify the user processing was interrupted
}
catch (ExecutionException ex) {
// Notify the user processing raised an exception
}
}
};
Addendum:
This can be extended to multiple tasks, it just requires changing how you approach setting the progress bar. Here's what comes to mind:
Have an array of completion counter, one per task.
int[] completions = new int[numTasks];
Arrays.fill(completions,0);
Start the SwingWorkers, each passed an index number. The process or done methods then call something like this to update the overall progress bar.
void update(int index, int percComplete) {
completions[index] = percComplete;
int total = 0;
for(int comp: completions)
total += comp/numTasks;
overallPB.setValue(total);
}
Optionally, display a JProgressBar per task.
Addendum 2:
If the tasks vary in completion time (eg, cache hit vs cache miss), you may want to investigate ProgressMonitor. It's a progress dialog that only appears if the task takes more than some (configurable, default 500ms) amount of time.
No need to call the frame inside invokeAndWait but you should update progress bar state like this.
try {
SwingUtilities.invokeAndWait( new Runnable() {
public void run() {
//update state of the progress bar here
}
});
} catch (InterruptedException e) {
} catch (InvocationTargetException e) { }