I've got a problem: I've got a jframe1 who calls at ActionPerformed the jframe2.
JFrames are threads or? and so I've tried in the jframe2 the wait() method, and then I would notify the jframe2's in jframe1..
my code in jframe2 (a method what run, when a button is clicked):
private void read(){
synchronized(jframe1){
try {
if(writer.checkLast() == null){
this.wait();
jLabel.setText(writer.getLast());
}
else{
jLabel.setText(writer.getLast());
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
But the Problem is, that if I use this.wait(); in jframe2, my jframe1 is also locked.. what I do wrong?
sry for my bad english, thanks if anyone have got an answer!
Frames are threads or?
No, absolutely not. There is one single thread in which all painting and user input events happen, the Event Dispatch Thread. However, this thread is different from the application's main thread, which is probably what lead you to believe that each frame has its own thread.
Since all events happen on the event dispatch thread, you don't have to do any synchronization, and your frames can call each other's methods without requiring any synchronization or notification. Which is the reason for the single threaded design in the first place (The general consensus is that a multithreaded GUI is nearly impossible to work with).
I get the feeling that you're trying to emulate the behavior of a modal dialog by using the wait() method, but as Michael explains well above, don't call wait on a Swing component and don't use Thread.sleep. Instead if you want to display another window modally use a JOptionPane or a modal JDialog. It's all well explained in the tutorials.
Related
I'm currently working with a thread control class someone else wrote. It is used for a java swing application. I have two methods, but I am confused as to why I am getting different behaviors from both. From what I know and read about the event dispatcher thread and Swing, there should be no difference in the two methods below. Apparently, this is not true.
//If this is the AWT Event Processing thread then run the code immediately,
//otherwise schedule it for later processing
public static void runWithEventThread(Runnable r)
{
if (EventQueue.isDispatchThread())
{
r.run();
}
else
{
EventQueue.invokeLater(r);
}
}
//Schedule the runnable for later processing by the AWT Event Queue
public static void runLaterWithEventThread(Runnable r)
{
EventQueue.invokeLater(r);
}
When using runWithEventThread() to display popups while updating GUI (new buttons/repainting), I found that the GUI would mess up sometimes. However when using runLaterWithEventThread(), it was all fine, no issues.
Only problem is that when using runLaterWithEventThread() I found that when I had multiple popups that would be displayed one after the other (after OK clicked) all popups were displayed at once.
From what I understand, both the methods should be doing the same thing. Can someone please explain what is going on
If your first method is executed from the event thread, it MAY act differently than the second method: If there are any events currently waiting on the event thread, those events will be processed BEFORE your run() method is executed if you use the second method, but if you use the first method, your run() method will be executed immediately, and any existing events on the queue will be run AFTER your run() method finishes.
I ran into what would SEEM to be a deadlock. Does a deadlock sound a little like:
Can't close window
Can't terminate without terminate button on the IDE
Blank and nothing happens, with no Exceptions or errors at all.
if those are the things that happen in a deadlock, then I probably have half the problem solved already. I have two threads that I know of are running: AWT-EventQueue-0 and frameThread.
This is using a custom library that I built and isn't fully developed yet (what you might call alpha-beta stage?). I decided to use it to make a Pong game. Actually my mentor assigned me the game. I'm just going to use my library with it.
My library uses Swing components and I doubt that has anything to do with it.
I would like to point out that the intrinsic locks according to the oracle tutorials state that
"When a thread invokes a synchronized method, it automatically acquires the intrinsic lock for that method's object and releases it when the method returns. The lock release occurs even if the return was caused by an uncaught exception."
before doing what this says, I had done a synchronized block to acquire the lock from the only thread I know of in my program that could have the lock. Failed. So I made the method synchronized and, well, the bullet points listed above happened.
my code is
// Threads
static ThreadManager tm = new ThreadManager() {
#Override
protected void runFrameThread() {//ThreadManager has threads in it that you can start.
while (true) { //These are just the abstract inherited methods the
Main.jpane.repaint(); // threads inside the manager call
}
}
#Override
protected void runMathThread() {
}
#Override
protected void runIntenseMathThread() {
}
};
// set frame rate
static {
tm.setFPS(30L);
}
public synchronized void draw(Graphics g) {// main problem: synchronized method here.
try {
wait(hertz);
} catch (InterruptedException e) {
System.err.println("ERROR: " + e.getLocalizedMessage());
e.printStackTrace();
}
g.setColor(rgb);
g.fillRect(this.x, this.y, width, height);
}
if that doesn't help, you can try looking through my code...
My Code Repository for the Pong game
My best bet is its something wrong with what Im doing to delay the method. what I want to do is have an update rate for every object at a set rate of 'x' hertz. It would be easier if it was a return type method (not void).
You state:
My library uses Swing components and I doubt that has anything to do with it
I fear that you may be very wrong. You appear to be completely blocking the Swing event dispatch thread (the EDT) with your while loop, and since this thread is responsible for all Swing graphics and user interaction, this will effectively freeze your GUI.
Rather than a while (true) loop that will block the EDT, use a Swing Timer instead.
Don't pause your graphics drawing as this will make your program seem poorly responsive.
Don't call synchronize from within a painting method.
Don't change the state of your objects from within a painting method such as paintComponent (i.e., don't call your updateGame() method from within paintComponent). This is because you never have full control over whether or even if this method will be called. It can be called out of your control by the JVM in response to a request by the OS to clean a dirty region, and the JVM may ignore your request for a repaint if repaint requests are stacking up.
This does appear to be a deadlock, and it most certainly has something to do with the use of Swing. The symptom of the whole application hanging is usually caused by the event dispatch thread (EDT) being deadlocked.
The problem appears to be in this code, which is in your Ball.java class:
public synchronized void draw(Graphics g) {
try {
wait(hertz);
} catch (InterruptedException e) {
...
}
It appears that the hertz field is not explicitly initialized, and thus it has its default value of 0L. A value of zero for the wait(timeout) method will block indefinitely, that is, it will wait with no timeout. It doesn't appear that this object is ever notified, so this method will hang the calling thread forever. This method is called from the JPanel.paintComponent method, which is called by the EDT, so this freezes the application's user interface.
Don't try to control the update rate by sleeping or pausing within the painting routines. The painting routines should always do as little work as possible, inspecting the current state of your model and issuing the appropriate graphics calls, and returning as quickly as possible.
Your program is multi-threaded, so you will need to synchronize your objects. The thread manager threads are updating the game objects and the EDT is painting using the game objects.
Access to your objects will occur on multiple threads, thus the need for synchronization. The synchronized blocks (or methods) should do as little as possible: get in, update (or paint), and get out. Code on the EDT should never call wait as that will probably cause poor repaint performance and responsiveness. The update threads should do as much computation as possible outside of the lock, and simply update the game objects with new values while the lock is held. This will minimize the amount of time the EDT is blocked acquiring the lock during the repaint cycle.
So I have this one button in a class that extends JPanel:
startTSP.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
scatterPlotPanel.findShortestPath();
}
});
And my problem is, that the method inside the actionListener (by the name findShortestPath() ), is one that has to constantly call repaint() on another JPanel. The problem is, that once I click the button startTSP, it doesn't repaint or anything. It just hangs until the method completes running (which can take a very long time given the input). The only time it repaints is right at the end. If it matters, I can post the method for findShortestPath() but I don't think it matters whats in it, because my question is, how do I get it to not hang and just carry out the method normally as if the method was called in the main class?
I'm sorry if the question is too vague, I will try my best to explain it if anyone doesn't understand (just mention so in the comments).
Also, basically what this method is doing is, permuting through an arraylist of coordinate points recursively, and finding the shortest path between the list of points. It is a simple brute force TSP solution.
If you have a long method executed in the event dispatch thread, it blocks the event dispatch thread, and thus prevents it from doing its job: dispatching other events, and painting the UI. This effectively freezes the GUI until the long method returns. So you must not have long, blocking methods in the event dispatch thread.
Use a SwingWorker to execute your long-running method in a separate thread. Or if what you want is simply a repetitive event to happen every N milliseconds on the EDT, then use a javax.swing.Timer.
You can try using another thread for painting on the other panel. This way you will have two independent threads doing different jobs.
You can use signals for communicating between these threads.
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.
After having some trouble with setting up a thread to start my MIDI sequencer I decided to simply remove it, although it would slow my UI down I would be able to use it correctly.
What I noticed however was that even when playing the Sequencer the UI was very much active, even if it was playing around 500 notes the UI worked perfectly fine.
Now I know that in C# if you are doing something intensive it is advisable to load it on a new Thread as it will free the UI. Is it the same principle in Java, it's really confused me. If so can someone explain how the UI is not being blocked?
Thanks
Edit:
The following code actually plays the Sequence
public static boolean Play() {
if(!_sequencer.isRunning()) {
try {
_sequencer.setSequence(_sequence);
_sequencer.start();
return true;
} catch (Exception e) {
Logger.Add(e.getMessage());
}
}
return false;
//Already running
}
Yes, it is the same theory. Only the Event Thread can modify the UI, and thus if you are doing anything on that thread, then you are preventing other events from working on the UI.
It may be easier to think about the Event Thread as a queue:
Show Form
Click Button
Do your work (Action)
Reset focus of Button
Update Progress Bar
Et cetera
If #3 takes long, then it may mean that your form will appear locked up. Obviously it completely depends on your definition of long. In general, it's better to work off of the Event Thread rather than on it.
It's definitely the same principal. Generally speaking you want to only do minimal work with the UI thread. If it ends up taking any significant time, it can cause the UI to be unresponsive and you can get a "Not Responding" error. You want to keep the UI thread as free as possible so it can respond to user interaction.
If your application has a graphical user interface, it's advised that you perform expensive calculations on a new Thread to keep your graphics from freezing. You can either create a SwingWorker, or use the Callable/Future idiom.
Yes, you're right. Read Threads and Swing for more info.