my program's UI freezes for some time after pressing a JButton. I discovered that a cause of this is a Semaphore clogging the Swing thread. This is the method containing the acquire() call on the Semaphore:
private void fetch(int numThreads) {
//some code here
sem = new Semaphore(numThreads);
for (int i = 0; i < model.getRowCount(); i++){
try {
sem.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
//some code here
}
And here is the only method that makes a call to fetch()
concFetchButt.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
switchButtonStates(false);
}
});
fetch(Integer.parseInt(threadsNumField.getText()));
}
As I understand, this code ends up running fetch() on the Swing thread, though, supposedly it has nothing to do with Swing.
I guess, my question is this: How do I run a method called from 'ActionPerformed()' of Swing on the main thread of the program instead of the Swing thread?
No need to specifically run that on the "main" thread. Simply run it on any other thread but the Swing UI thread.
The most simple solution to get there:
add an ExecutorService to your class
put that code fetch(Integer.parseInt(threadsNumField.getText())); into a Runnable object
Submit that Runnable to the ExecutorService
Along the lines of:
private final ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.execute(new Runnable() {
public void run() {
fetch(Integer.parseInt(threadsNumField.getText()));
}
});
Related
I've got a class that creates and runs a thread, which creates a GUI.
I want the initial class to remain suspended until the GUI is closed (OK button for example)
I tried thread.join(); but since the GUI is created on the event dispatch thread this does not seem to work, and the class continues as the GUI pops up.
private void CreateAndRunThread(){
GUIMaker GM= new GUIMaker(data);
GM.run();
try {
TFM.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
MessageDialog.showDialog("GM Done");
}
thread's GUI creation:
#Override
public void run() {
//Schedule a job for the event dispatch thread:
//creating and showing this application's GUI.
SwingUtilities.invokeLater(new Runnable() {
public void run() {
//Turn off metal's use of bold fonts
UIManager.put("swing.boldMetal", Boolean.FALSE);
CreateAndShowGUI(frame); //adds frame, packs and sets visible
}
});
}
Use CountDownLatch:
CountDownLatch latch = new CountDownLatch(1);
Call the following in the inital class to block:
latch.await();
Call the following when the GUI is closed:
latch.countDown();
Also it seems that you are not starting thread properly. You need to call GM.start() method instead of GM.run().
This question already has an answer here:
nested postDelayed / Runnable / Handler Android
(1 answer)
Closed 4 years ago.
Basically , i have 5 Runnables for each user.
Inside each Runnable, There must be waiting for a variable to change until it continues. I'll be using either a Semaphore or a CountDownLatch.
So inside each Runnable there is a runnable for waiting.
Here's an example. r1 is a runnable supposed to be user so never ending.
final Handler handler = new Handler();
Runnable r1 = new Runnable() {
#Override public void run() {
// here must be another runnable for waiting
Runnable r2 = new Runnable() {
#Override public void run() {
if (condition) {
latch.countDown();
// ending the runnable
handler.removeCallbacks(r2);
} else {
// keep waiting
handler.postDelayed(r2, 1000);
}
}
}
latch.await();
// restarting the runnable
handler.postDelayed(r1, 1000);
}
}
The problem when using latch.await() is that is running in main thread so blocking the UI.
Any idea how to starts those runnable in different threads?
What i wanted to do is a non stop running Thread that somewhere needs to wait a variable to change so it continues other instructions. Somewhere in the UI when a button is clicked ,a semaphore gets incremented. And in the thread it waits until it is available. Here's the solution i made
Semaphore sem = new Semaphore(0,true);
//somewhere in UI sem.release();
Thread thread = new Thread()
{
#Override
public void run() {
try {
while(true) {
sleep(1000);
semaphore.acquire();
// when updating the UI is needed
runOnUiThread(new Runnable() {
#Override
public void run() {
// work
}
});
}
} catch (InterruptedException e) {
}
}
}
I'm trying to make an JavaFX application that tracks the movement of my mouse for this im using this code in the controller class:
new Thread(new Runnable() {
#Override public void run() {
while (Main.running) {
Platform.runLater(new Runnable() {
#Override
public void run() {
try {
label.setText(MouseInfo.getPointerInfo().getLocation().toString());
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}
}).start();
But it couses my application to lag big time.
How should i fix this lag problem?
Thanks i fixed it:
new Thread(new Runnable() {
#Override public void run() {
while (Main.running) {
Platform.runLater(new Runnable() {
#Override
public void run() {
label.setText(MouseInfo.getPointerInfo().getLocation().toString());
}
});
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
What you doing is letting Javafx Application thread Thread.sleep(1000); <-wait
Any long term action you shoud put OUT of JFX-AT. And only update your ui components on it.
new Thread(()->{
while(Main.running){
Platform.runLater(()->{
//updateui component
//this is updating on FXAT
});
Thread.sleep(time)//This way you dont let JFXAT wait
}
}).start();
//Not sure if formatted and curly braces correctly.Bud you hopefully understand.Make sure you know which thread you let wait.Otherwise you wont be able to recieve events from paused jfxat.
You should put your Thread.sleep() call in your while loop and not in your Runnable, otherwise the loop keeps posting a lot of runLater tasks and those tasks stops the event thread for 1000ms after updating your mouse position
You call Thread.sleep(long) inside a Runnable that will be executed on the UI thread. If the thread is sleeping, it can't do anything else but sleep there. If you want your label to update every 1000 milliseconds, you can use the java.util.Timer class to make that happen.
In my application i have two jtextpanes and i have a executorservice instacne which contains few task. I want to assure that all the task in the executorservice instance are completed before executing the FocusListener focusGained method of any jtextpanes. Also i add some more task to the executorservice when focusLost method is called.
Code
top.addFocusListener(new FocusListener()
{
public void focusLost(FocusEvent e)
{
if (ecaViewControl.isInitialized())
{
stopRecording();
executor.execute(new Runnable()
{
public void run()
{
ecaViewControl.save(top);
}
});
executor.execute(new Runnable()
{
public void run()
{
ecaViewControl.closeDocument();
}
});
}
}
public void focusGained(FocusEvent e)
{
//Need to have completed all the task in executor service before EDT executes the code in here
});
}
if you do know the number of tasks to be finished, consider using of CountDownLatch
so your code might look like:
public void run() {
try {
// do something here
} finally {
latch.countDown()
}
}
then in the code you're waiting for tasks to complete - simply wait for latch:
latch.await();
or, instead use CompletionService if you may live without executor.
I would like to get a recurring call back to invalidate a view. I am sure there is a neat way to do this. I am currently doing this and would like a neater / better solution if possible?
new Thread()
{
#Override
public void run()
{
while (!Thread.currentThread().isInterrupted())
{
handler.post(new Runnable()
{
public void run()
{
BannerButton.this.invalidate();
}
});
try
{
Thread.sleep(50); // yields 20 fps
} catch (InterruptedException e)
{
Thread.currentThread().interrupt();
}
}
}
}.start();
For a single shot timer on the UI thread, I do this: (But I cant find a way to do this with repeats)
(new Handler()).postDelayed(new Runnable()
{
#Override
public void run()
{
// Do stuff
}
}, SPLASH_SHOW_TIME);
Timer looked good, but it calls on a background thread.
Thanks.
Your second try using Handler is already correct. Just store the Handler and the Runnable in a field, and then inside the run() method (possibly at the end), call again
handler.postDelayed(runnable, 1000);
Look at the View.postInvalidate() method. This is different from invalidate() as you can do it from any Thread you want. It just posts an invalidate() message in the UI thread Looper
Concerning your second question simply post with some delay the same Runnable at the end of the Runnable in your Handler