I learned about how swing isn't thread-safe. Delving deeper, I discovered that every modification to a swing component must be done on the Event Dispatch Thread in order to prevent various issues associated with multithreading. However, the information seemed to completely stop there. There doesn't seem to be a good tutorial that explains how to do this anywhere accessible on the internet.
Patching together information from code posted in relation to other issues, it seemed that I would have to put an untidy block of code around every single swing modification in my program (like this example from my own code):
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
setTitle("Frame title");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
setSize(800, 480);
setLocationRelativeTo(null);
setIconImage(Toolkit.getDefaultToolkit().createImage(ClassLoader.getSystemResource("Frame icon.png")));
}
});
} catch (Exception e) {
e.printStackTrace();
}
Basically, is this right? Do I have to put that code (or the equivalent with invokeLater) around every modification to a Swing component in my code?
Also, why doesn't Swing do this automatically?
The trick is that when swing calls you it will ALWAYS be in the EDT, so you don't have to worry about it.
However if you are in a timer or an action triggered by some other external event, your main thread or any other thread you've created then yes, you have to use invokeLater or invokeAndWait.
In other words, yes swing does do "it" automatically. Needing to use invokeXx is so rare that if swing were to do it internally it would waste too much time.
Many java programmers never figure this out and it can cause some pretty nasty hard-to-find problems with drawing your GUI. I do wish swing threw an exception when you called it not using the EDT--Java would have a better reputation when it came to professional GUIs if it did because there would be less crap out there.
note that any code executed from event handlers is already run in the EDT (the Event in the acronym)
this means that for general use (while you don't mess with swingworkers and threadpools and such) you are always inside the EDT
and you can always query if you are in the EDT with SwingUtilities.isEventDispatchThread()
also note that in your code the call to invokeAndWait will fail and throw an error when you are in the EDT already
Basically, you dont draw or update the GUI from outside of the EDT.
You use SwingUtilitis.invokeLater() from another thread to ensure the GUI drawing or updating code is run on the EDT.
Not all your UI code must be part of a runnable in an invokeLater call. That is simply because a large part of your program will be run on the EDT anyway. You need to dispatch messages to the EDT only when you are on a different thread.
Related
I've recently started learning and exploring the basics of GUI programming in Java.
Having been programming for a while I have only done backend work or work and as a result the closest I've gotten to user interfaces is the command console (embarrassing I know).
I'm using Swing and as far as I can gather that means by extension I am also using AWT.
My question is based on this piece of code:
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new frame.setVisible(true);
}
} );
I have been researching this for a while as I wanted to fully understand this strange piece of code and have come across the term 'Event-Dispatching Thread' multiple times. Correct me if I'm wrong but as I understand it; it has to do with using multiple threads and how Java Swing interprets those threads. I gather as well that the above code is used to make sure all the threads are 'safe' before it creates the window, hence the invokeLater?
I have read that:
"You can only call methods that operate on the frame from the Event-Dispatching Thread"
and that only under certain circumstances can you call methods that operate on the frame from the main method.
Can somebody please clarify to me what exactly the Event-Dispatching Thread is?
How it relates to multiple threads of execution and how those threads are not safe to be called from the main method? Also why do we need this invokeLater?
Can we not just create the window as any other object?
I've hit a bit of a road block in my research as I'm not grasping these relations and ideas.
A side note is that I like to base my knowledge on in-depth understanding as I believe this leads to the best overall outcome and as a result the best programs. If I understand in-depth how something works then you can use the tips and tweaks effectively rather than just parroting them back in to code, so please don't be afraid to give me some extra in-depth explanations and broaden my knowledge.
Thank you.
The event dispatch thread is a special thread that is managed by AWT. Basically, it is a thread that runs in an infinite loop, processing events.
The java.awt.EventQueue.invokeLater and javax.swing.SwingUtilities.invokeLater methods are a way to provide code that will run on the event queue. Writing a UI framework that is safe in a multithreading environment is very difficult so the AWT authors decided that they would only allow operations on GUI objects to occur on a single special thread. All event handlers will execute on this thread and all code that modifies the GUI should also operate on this thread.
Now AWT does not usually check that you are not issuing GUI commands from another thread (The WPF framework for C# does do this), meaning it's possible to write a lot of code and be pretty much agnostic to this and not run into any problems. But this can lead to undefined behavior, so the best thing to do, is to always ensure that GUI code runs on the event dispatch thread. invokeLater provides a mechanism to do this.
A classic example is that you need to run a long running operation like downloading a file. So you launch a thread to perform this action then, when it is completed, you use invokeLater to update the UI. If you didn't use invokeLater and instead you just updated the UI directly, you might have a race condition and undefined behavior could occur.
Wikipedia has more information
Also, if you are curious why the AWT authors don't just make the toolkit multithreaded, here is a good article.
EventDispatchThread (EDT) is special thread reserved only for Swing GUI and *Swing's related events e.g. create/change/update Swing JComponents, more for asked questions here and here
all output to the GUI from BackGround Tasks, Runnable#Thread must be wrapped into invokeLater(), from synchronized Objects into invokeAndWait();
I'm new to Java and after reading many articles about threads and swing I understood that all the invocations of Swing methods should be done on the EDT because Swing is not thread safe. however, I already wrote a couple of quite long Swing applications before reading about the EDT. and all of my applications ran quite fine. So my question is were my Swing applications running on the EDT by default or were they running on a different thread and i was just lucky not to have any issues with them?
Like for example if I add a JButton to a JPanel or JFrame, or if I simply call a JTextField's Field.setText(), will these operations be running on the EDT by default or no?
and if the answer is no, then do I have to explicitly send all my Swing component's methods implementations to run on the EDT by invoking SwingUtilities.invokeLater()
Thanks
Remember objects don't live on threads, only execution of methods happens on a thread.
All action emerging (through listeners) from swing components automatically run on the EDT.
For instance a button you click, the onClicked() function will already run on the EDT so you don't need to do anything.
If you don't create any threads explicitly, your basic application will have a main thread and an EDT (and many other threads that you don't accidentally get your code executed on, until you start using extra frameworks).
The thing you have to do manually is construct the GUI on the EDT. As you can see here this can be done in your main thread as follows:
SwingUtilities.invokeLater(new Runnable() {
public void run() {
MyWindow window = new MyWindow ();
window.setVisible(true);
}
});
If you fail to use the EDT correctly. Everything will seem to work fine, but every now and then you can get very strange behavior (because two threads will be doing things instead of one).
So in summary you have to use invokeLater(), or in some exceptions invokeNow() in the following cases:
Constructing Swing components from the main thread.
Calling swing components from your personally created threads.
Calling swing components from events on threads created by frameworks.
This question contains some tools that can help you automatically detect errors (not all though).
where my Swing applications running on the EDT by default or were they running on a diffrent thread and i was just lucky not to have any issues with them?
They were mostly being ran on the EDT. All the painting and updating that Swing does by itself is on the EDT. Anything you do specifically in your code base that you know wasn't on the EDT, is the code that was not on the EDT. So these would be actions like querying the text of a JLabel, or setting the text of a JLabel, or initializing the JLabel itself.
The various listener methods that are executed by Swing which you have implemented in your code base are however executed on the EDT (as long as Swing called it, not yourself). So in these methods you can query/modify Swing components, but remember to properly transfer in and out any data you give to a Swing component or queried from a Swing component in a thread-safe manner.
Like for example if I create a JButton and add it to a JPanel or JFrame, are these operations running on the EDT by default or no?
The initialization of the objects happens on whatever thread you created them on, and so are the rest of the modifications of the Swing objects (like adding one component to another). I do not know of any Swing components whose public method implementations are wrapped in their own invokeNow() or invokeLater() call, so it's best to assume all portions of the actions happened on whatever thread you called the original methods on.
do I have to explicitly send all my Swing components and methods to run on the EDT by invokingSwingUtilities.invokeLater()
Yes, or invokeNow()
Components will be accessed from within the thread context they are called, wch leads to a problem...
All Swing components (or enough not to matter) MIST be accessed within the context of the Event Dispatching Thread once they have been added to a displayable container (attached to a native peer).
This makes Swing components NOT thread safe and you are responsible for ensuring that they are modified/accessed from the EDT correctly, the framework will NOT do it for you
Take a look at Concurrency in Swing for more details
When I start my GUI interfaces, what can happen if I don't use invokeLater?
Does that mean all rest of the GUI paints/updates/etc. will be in the main thread?
Will calling a repaint outside of an invokeLater make all subsequent calls fall into the main thread?
Basically this:
void main()
{
JFrame jmf();
setVisible(jmf);
}
------------- VS -------------
void main()
{
SwingUtilities.invokeLater(new Runnable(){
run(){
JFrame jmf();
setVisible(jmf);
}
}
});
NOTE: In cases with small GUI, I if I don't put the invokeLater it seems to work fine. And in fact the application doesn't terminate although the last line of the main is executed.
I have read quite a few articles on why we should use it pertaining to the fact that Swing is not thread safe (it is single threaded and so on), but I really didn't read the repercussions of not calling invokeLater (partially because of my limited knowledge in Threads)
The reality is, nothing might happen or the world will end. It's next to near impossible to predicate, this is the nature of multi-threaded environments...
Unless you are doing some really dynamic setups, until the a frame is made visible it "should" be okay not to do it within the context of the EDT.
The problem comes down to the fact that different platforms are implemented differently (at the native level). For example, the original requirement for using invokeLater when starting your UI seems to have come from deadlocks on the Sun OS many years back.
I've also seen some issues with Java 7 (but my predecessors idea of the thread was weird to say the least). The general advice is, use invokeLater to create and display your UI. Run all UI code within the context of the EDT
It will also reduce the risk of you having to spend weeks trying to replicate and track down those weird anomalies (by running you all you UI code from within the EDT)
Updated based on comments from the OP
repaint makes a request to the RepaintManager, that makes decisions about what and when something should be paint. It will actually post a "paint" event directly on to the Event Queue, which is then processed by the Event Dispatching Thread, so repaint is actually on (of the few) thread safe methods...
Take a look at
Painting in AWT and Swing
Initial Threads
Will the real Swing Single Threading Rule please stand up?
Why is Swing threading model considered wrong and how should it be?
The general advice would be, you should use invokeLater because that's how the API has been designed, doing anything else is inviting problems...
I am using the following codes, to replace a JLabel each 0.5 seconds, with the same sentence but with another dot.
Runnable r1=new Runnable() {
#Override
public void run() {
while(true){
try {
connectionStatus.setText("Connection Established...");
Thread.sleep(500L);
connectionStatus.setText("Connection Established.");
Thread.sleep(500L);
connectionStatus.setText("Connection Established..");
Thread.sleep(500L);
} catch (InterruptedException ex) {
}
}
}
};
Thread th1=new Thread(r1);
th1.start();
Is this the real purpose from using threads? Does this affect the speed of the program? If the thing that I'm doing is so stupid, is there any other way to do such stupid things?
Is this the real purpose from using threads?
If you want these operations to run in parallel then the answer is yes
is there any other way to do such stupid things?
If you update your label at a fixed intervals then you should probably go for using Timers instead
On a side note:
You should avoid using while(true) when doing multithreading, you should either define a stop boolean that you test in the loop or use Thread.interrupted() if you extend the Thread class
When updating UI elements from non EDT thread, you should use SwingUtilities.invokeLater
There are several issues with this code.
Swing components should be accessed/updated on the Event Dispatch Thread and are not thread-safe. So starting another Thread to update your JLabel is simply not done. See the 'Concurrency in Swing' tutorial for more information
Even if you would call the code above on the EDT, you would not see any updates of the JLabel as the Thread.sleep would block the EDT, and avoiding a repaint.
So the solution is to use the javax.swing.Timer class, which allows to perform operations on the EDT at regular intervals, and does not block the EDT in between. See also the Timer tutorial. As a side effect, using timers avoids the while(true) loop which would never end.
You can find a more complete answer here.
Try using a Timer from Swing library instead. It's generally a better idea to use these for GUI-related tasks. This will especially come in handy when you try to use timed events on multiple components as all Timers share the same timer thread.
It also provides a flexible and intuitive programming model based on listeners.
No need to reinvent the wheel.
Timer tutorial
EDIT:
A little followup on the wheel reinvention part. You should also take Andrew Thompson's suggestion into consideration. There are components in Swing that have been designed specifically to indicate progress. It's unnecessary to do it using a label, as you're trying to do. Take a look at JProgressBar. It's going to be simple and it will look more professional.
First one suggestion, rather use something like this:
while(!isStopped) {
// do some work
}
With your approach you just created infinity loop.
Note: Have look at Java Timer. It's very usefull and efficient.
Try this,
You will need the above approach if your purpose is parallel processing.
You have given while (true) , which will lead to a Infinite loop, you must control it,
its better to have a boolean variable to control the nos. of iteration of the while loop.
Keep you non-ui thread processing OUT of the Event Dispatcher Thread, else you will make the GUI hang till
your thread has finished its run() method. In your case its Infinite, as while (true).
If you want to sync the non-ui work and ui work, then you can use Handler or Swing-Worker.
Last but not the least, Take a look at TimeTask, see this link
http://enos.itcollege.ee/~jpoial/docs/tutorial/essential/threads/timer.html
I read somewhere that for any thread that affects the visuals of the gui it should be ran in the EDT using SwingUtilities.invokeAndWait/invokeLater
For a basic gui, is it necessary to put something like new SwingGUI().setVisible(true); in the line of the EDT using invokeAndWait? Just to display?
Does this count?
The short answer to your question is: yes, even calling setVisible should happen on the EDT. To find out whether the current thread is the EDT, you can use the EventQueue#isDispatchThread method
Some reference links:
Multithreaded Swing Applications
Threads and Swing
Concurrency in Swing
Edit:
after reading the links I provided, it seems some of the articles on the Oracle site are outdated as in they still document you can create Swing components on another thread. There is a stackoverflow question on this which contains some nice answers and links to blogposts and articles about the 'new' policy (new as in a few years old)
Yes, if you touch a Swing object you have to do it on the EDT. In most cases you are already there, but if not, use the SwingUtilities classes. The reason for this is that the Swing classes are not multi-threaded, so you are likely to cause nasty problems if you access it on other threads. And it could be that setVisible() is doing a lot of things under the covers to make something display (like re-laying things out). Better to be safe.
Anything that is called from your
public static void main(String[] agrs) {
directly (without spawning another thread or using invokeLater) is running on the main thread.
Accessing GUI objects with the main thread while they may be being accessed (simultaneously) by the EDT (which is triggered by user input) can cause threading issues. Calling invokeLater causes tasks (runnables) to run on the EDT, preventing simultaneous access by other EDT tasks ie. button presses etc.
If you can be sure the EDT is not busy (before the first window is setVisible(true)) you can access the GUI from the main thread. If you can be sure the EDT has no reference to the component you're working on (it is out of EDT's scope) ie. before it's added to any container, you can access it from main thread without the EDT accessing it simultaneously, as the EDT has no way to reach it.
Everything that access Swing objects should do so via the Event Dispatch Thread (EDT). There is one small exception to this (which I'll mention later). The purpose of the EDT is to process any events that may occur due to IO (mouse and keyboard events). Quite a lot of the time this can mean altering the layout of your GUI. Swing was not developed to be thread-safe, meaning that that if two thread try to modify the same component at the same time then you can end up with a corrupted GUI. Since there is already one known thread to be accessing Swing components (the EDT), no other thread should attempt to modify them or even read their state.
Now, to the exceptional case when you can manipulate Swing objects outside of the EDT. Before any components have become visible it is not possible for IO to be triggering events. Therefore, the main thread can setup a Swing GUI and then set a single JFrame to be visible. Since there is now a visible frame IO events can occur and the main thread should not try to modify any more Swing components. The should only use this option to get a GUI started, and really only with toy problems.
What I'm saying is that the following is fine and won't cause problems if you're just playing around with stuff.
public static void main(String[] args) {
// create components
JFrame f = new JFrame();
...
// do layout and other bits of setup
// show gui to user
f.setVisible(true);
}