Hi I'm trying to understand EDT vs. Multithreading, hoping someone could correct me if this doesn't make sense.
First I put the creating process of the GUI in its own thread which is
then added to the EDT
public class Main
{
static ServerGui serverGui;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
try{
serverGui = new ServerGui();
serverGui.frame.setVisible(true);
}
catch(Exception e)
{
e.printStackTrace(); }} });}}
In my GUI I created the ServerDataHandler object sdh
public class ServerGui {
public ServerDataHandler sdh = new ServerDataHandler();
public JFrame frame;
public ServerGui() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame();
frame.setType(Type.NORMAL);
frame.setBounds(100, 100, 800, 600); } }
Now from another thread, I wish to work with that sdh object, and use some of the methods
that it has.. e.g. sdh.writeToFile(); so here are my questions
as I want to use the same object do I need to do it like I've down below?.
Do I need to synchronize the ServerDataHandler class when e.g. in my case the method writes down to a file? I suspect I do
When would I need to use 'invokeLater'? is that just when I'm changing in the actual GUI?
Client
public class Client implements Runnable {
private Socket clientSocket;
public Client(Socket clientSocket) {
this.clientSocket = clientSocket;
#Override
public void run() {
Main.serverGui.sdh.writeToFile();} }
Classes and objects
The Main, Client, ServerGui, and ServerDataHandler classes you have created are just that, classes. When you call a class's constructor, you create an object that is an instance of the class.
Each thread weaves its way through the objects in the JVM, following the execution path as a method in one object calls a method in another object. So objects just sit in the JVM and are not specifically bound to threads.
Threads
Also inside the JVM live multiple threads. You can create and destroy them yourself, using methods in the java.lang.Thread class. But the main thread and the The Event Dispatch Thread are created for you.
An object that's an instance of a Runnable class can be created in one thread and then handed over to be run by another thread. This is what you do when you call SwingUtilities.invokeLater. You create an anonymous Runnable object and schedule its run() method to be invoked by the Event Dispatch Thread.
Event Dispatch Thread
The reason to do this is that Swing objects are not thread-safe, i.e. not written to be handled by more than one thread at a time. Their methods, like setVisible(true) should be called by the Event Dispatch Thread, one at a time.
The event handling methods in listeners that you assign to Swing objects will be called on the Event Dispatch Thread. While they're being called, the Event Dispatch Thread is busy weaving through your event handler code, and not available to draw pixels on the screen or react to button clicks. Therefore, if you want your User Interface to be responsive, you should keep your event handling code short and quick.
If you want to run lengthy tasks, like reading a long file, or chat with the server, you should create and start a new Thread for this task to run in. This is called a Background or Worker thread. You can create a Runnable class for the job you want to run and feed it to the Thread you've created.
A somewhat more high-level way to schedule tasks is through the classes in the java.util.concurrent package, in particular the ExecutorService.
A good tutorial with more information is Concurrency in Swing
Related
I have something I can't understand: my Swing GUI contains a 'play' and 'pause' button. I have also a static variable that defines 'ON' and 'OFF' states. (The main program generates the GUI).
By cliking on 'play' I change the state of my static variable to 'ON' and I launch a time-consuming process in a thread that also modifies the GUI. As long as the static variable is 'ON' loops in the same process. Clicking on 'pause' would change the static variable to OFF.
But by clicking on 'play' the GUI is freezing and consequently:
The GUI doesn't update
The process can't be 'paused' with my 'pause' button.
I have heard about EDT and SwingWorker but I you have a simple way to do it I take it.
Thank you for your help and forgive my bad english...
The problem is that you're doing the intensive, time-consuming work on the same thread responsible for updating the GUI. SwingWorker allows you to move time-consuming tasks to a separate thread of execution, thereby leaving the UI thread to do its thing uninhibited.
However, it does add a further complication: affinity. Calling methods on UI components generally requires that you do so from the UI thread. Therefore, you need to use special functionality to get back to the UI thread from the worker thread. SwingWorker also gives you this ability.
I suggest you read through this documentation.
You need to read Concurrency in Swing to understand how the EDT and SwingWorkers operate.
All GUI updates are executed on the EDT so when you click a GUI component any method that this calls will be executed on the EDT. If this is a time consuming process then this will block the EDT from executing any futher GUI updates. Hence your GUI is freezing and you can't click the pause button.
You need to use SwingWorker to execute the time consuming process on another thread. The link I provided above details how to do this.
You should not start long-running processes in Swing’s event handler because it will freeze your GUI, you know that now. :) Start it in a new thread. You only need to use a SwingWorker if you’re planning on manipulating the GUI from the worker thread (because Swing is not thread-safe).
This is a pretty straightforward reason: while Java is working on your time-consuming process, it isn't able to update the GUI. Solution: run the time-consuming process in a separate thread. There are a bunch of ways to program that, and it would probably depend somewhat on how your program is written.
The event dispatch thread (EDT) is the only thread in which it's safe to read or update the GUI.
The pause button should be setting the on/off variable in the event dispatch thread.
The time-consuming operation, and the loop, should not be in the EDT. (The loop should also not be running continuously doing nothing but check the variable, or it can easily eat all your CPU. If it has nothing else to do it should check, and then call Thread.sleep() for some length of time (say 100ms).)
If you can prove that the on/off variable is being set to OFF, but that nonetheless it's always read as ON, it may be that the variable's value is not being copied from the EDT to the worker thread. Make it volatile, or synchronize access to it, or use an AtomicReference, or read it in the EDT using SwingUtilities.invokeAndWait().
SwingWorker probably is the simplest way to go, here. Implement your time-consuming operation, and the on/off check, in the doInBackground() method, and your GUI update in the done() method.
public enum State {
RUNNING, STOPPED
}
public class ThreadSafeStateModel {
private State state = State.STOPPED;
public synchronized void stop() {
state = State.STOPPED;
}
public synchronized void start() {
state = State.RUNNING;
}
public boolean isRunning() {
return state == State.RUNNING;
}
}
public class ExpensiveProcessWorker extends SwingWorker<Void, Void> {
private final ThreadSafeStateModel model;
public ExpensiveProcessWorker(ThreadSafeStateModel model) {
this.model = model;
}
#Override // Runs in background
protected Void doInBackground() throws Exception {
while (model.isRunning()) {
// do one iteration of something expensive
}
return null;
}
#Override // Runs in event dispatch thread
protected void done() {
// Update the GUI
}
}
public class StopButton extends JButton {
public StopButton(final ThreadSafeStateModel model) {
super(new AbstractAction("Stop") {
#Override
public void actionPerformed(ActionEvent e) {
model.stop();
}
});
}
}
public class StartButton extends JButton {
public StartButton(final ThreadSafeStateModel model) {
super(new AbstractAction("Start") {
#Override
public void actionPerformed(ActionEvent e) {
model.start();
new ExpensiveProcessWorker(model).execute();
}
});
}
}
(A lot could be done to clean this up depending on the real application, but you get the idea.)
#Override
public void actionPerformed(ActionEvent e) {
new Thread() {
public void run() {
//your code which runs on click event
}
}.start();
}
I have something I can't understand: my Swing GUI contains a 'play' and 'pause' button. I have also a static variable that defines 'ON' and 'OFF' states. (The main program generates the GUI).
By cliking on 'play' I change the state of my static variable to 'ON' and I launch a time-consuming process in a thread that also modifies the GUI. As long as the static variable is 'ON' loops in the same process. Clicking on 'pause' would change the static variable to OFF.
But by clicking on 'play' the GUI is freezing and consequently:
The GUI doesn't update
The process can't be 'paused' with my 'pause' button.
I have heard about EDT and SwingWorker but I you have a simple way to do it I take it.
Thank you for your help and forgive my bad english...
The problem is that you're doing the intensive, time-consuming work on the same thread responsible for updating the GUI. SwingWorker allows you to move time-consuming tasks to a separate thread of execution, thereby leaving the UI thread to do its thing uninhibited.
However, it does add a further complication: affinity. Calling methods on UI components generally requires that you do so from the UI thread. Therefore, you need to use special functionality to get back to the UI thread from the worker thread. SwingWorker also gives you this ability.
I suggest you read through this documentation.
You need to read Concurrency in Swing to understand how the EDT and SwingWorkers operate.
All GUI updates are executed on the EDT so when you click a GUI component any method that this calls will be executed on the EDT. If this is a time consuming process then this will block the EDT from executing any futher GUI updates. Hence your GUI is freezing and you can't click the pause button.
You need to use SwingWorker to execute the time consuming process on another thread. The link I provided above details how to do this.
You should not start long-running processes in Swing’s event handler because it will freeze your GUI, you know that now. :) Start it in a new thread. You only need to use a SwingWorker if you’re planning on manipulating the GUI from the worker thread (because Swing is not thread-safe).
This is a pretty straightforward reason: while Java is working on your time-consuming process, it isn't able to update the GUI. Solution: run the time-consuming process in a separate thread. There are a bunch of ways to program that, and it would probably depend somewhat on how your program is written.
The event dispatch thread (EDT) is the only thread in which it's safe to read or update the GUI.
The pause button should be setting the on/off variable in the event dispatch thread.
The time-consuming operation, and the loop, should not be in the EDT. (The loop should also not be running continuously doing nothing but check the variable, or it can easily eat all your CPU. If it has nothing else to do it should check, and then call Thread.sleep() for some length of time (say 100ms).)
If you can prove that the on/off variable is being set to OFF, but that nonetheless it's always read as ON, it may be that the variable's value is not being copied from the EDT to the worker thread. Make it volatile, or synchronize access to it, or use an AtomicReference, or read it in the EDT using SwingUtilities.invokeAndWait().
SwingWorker probably is the simplest way to go, here. Implement your time-consuming operation, and the on/off check, in the doInBackground() method, and your GUI update in the done() method.
public enum State {
RUNNING, STOPPED
}
public class ThreadSafeStateModel {
private State state = State.STOPPED;
public synchronized void stop() {
state = State.STOPPED;
}
public synchronized void start() {
state = State.RUNNING;
}
public boolean isRunning() {
return state == State.RUNNING;
}
}
public class ExpensiveProcessWorker extends SwingWorker<Void, Void> {
private final ThreadSafeStateModel model;
public ExpensiveProcessWorker(ThreadSafeStateModel model) {
this.model = model;
}
#Override // Runs in background
protected Void doInBackground() throws Exception {
while (model.isRunning()) {
// do one iteration of something expensive
}
return null;
}
#Override // Runs in event dispatch thread
protected void done() {
// Update the GUI
}
}
public class StopButton extends JButton {
public StopButton(final ThreadSafeStateModel model) {
super(new AbstractAction("Stop") {
#Override
public void actionPerformed(ActionEvent e) {
model.stop();
}
});
}
}
public class StartButton extends JButton {
public StartButton(final ThreadSafeStateModel model) {
super(new AbstractAction("Start") {
#Override
public void actionPerformed(ActionEvent e) {
model.start();
new ExpensiveProcessWorker(model).execute();
}
});
}
}
(A lot could be done to clean this up depending on the real application, but you get the idea.)
#Override
public void actionPerformed(ActionEvent e) {
new Thread() {
public void run() {
//your code which runs on click event
}
}.start();
}
I'm building a Swing application and one part of the functionality should be to process and output some text visually and audibly (using Mary TTS). I need some advice on the best way for the GUI and text processing classes to communicate.
The GUI class is a subclass of JPanel. Within that I have a class implementing Runnable, called LineProcesser, which prepares the text to be dispatched to an audio player. I'm using a thread executor to keep this off the EDT (that may not be the best way but it seems to achieve the result I'm after).
My intention is for LineProcessor to run through all the text and update a JTextArea at the end of each line. Additionally it will need to halt and wait for user input at certain points. After the user input has been completed the GUI class should tell it to resume processing.
The following code illustrates what I currently have:
public class MyPanel extends JPanel {
ExecutorService lineExecutor = Executors.newSingleThreadExecutor();
Runnable lineProcessor = new LineProcessor();
public class LineProcessor implements Runnable {
private int currentLineNo = 0;
public LineProcessor() {
// ...
}
#Override
public void run() {
// call getText();
// call playAudio();
currentLineNo++;
}
}
}
private JButton statusLbl = new JLabel();
private JButton mainControlBtn = new JButton();
private void mainControlBtnActionPerformed(ActionEvent evt) {
if (mainControlBtn.getText().equals("Start")) {
lineExecutor.submit(lineProcessor);
mainControlBtn.setText("Running");
}
}
}
How can LineProcessor notify GUI components that they need to change and how can it be paused and restarted from within the GUI? I'm confused as to whether I need a Swing Worker, property/event listeners or something else? The examples I've read sort of make sense but I can't see how I can apply them to the code I have here.
All you need to do is wrap any Swing calls in a Runnable, and queue it on the EDT via SwingUtilities.invokeLater(myRunnable);. That's it. No need for a SwingWorker.
e.g.,
public class LineProcessor implements Runnable {
private int currentLineNo = 0;
Runnable LineProcessor = new LineProcessor(); // won't this cause infinite recursion?
public LineProcessor() {
// ...
}
#Override
public void run() {
// call getText();
// call playAudio();
currentLineNo++;
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// *** Swing code can go here ***
}
});
}
}
You will have to use both SwingWorker and Event methodology.
Place your long running code in Swing Worker.
Create new property change Event, listener, manager
In your SwingWorker, when the change event occurs, call PropertyChangeManager to notify all the liseners.
All GUI components which wants to be notified with the event should register themselves with the PropertyChangeManager.
Your PropertyChangeManager will call customProperyChange method of the PropertyChangeListener and will pass the properyChangeEvent
What you are looking for is a SwingWorker. This class allows to perform the work on a worker thread, having periodical updates on the EDT, and in the end update the EDT as well.
Several examples are available on SO and in the Swing tutorials. Just a few links
The 'How to use progress bars tutorial', which happens to update a text area as well
The 'Concurrency in Swing' tutorial, a must-read if you start with SwingWorker
The SwingWorker javadoc
Reporting progress can be done with the publish method, these results will be passed to the process method in which you can update the UI. At the end, the done method is called allowing you to perform some final UI updates.
For the pause/restart functionality ... you can use an invokeAndWait in the doInBackground method with a blocking method call (for example showing a JOptionPane asking for user input). But if you start using invokeAndWait in the doInBackground it might be overkill to use the SwingWorker and you can simply opt for the approach #Hovercraft Full Of Eels suggested
Let's say I have one thread running (I'm creating many instances of this thread), and inside that I instantiate a JForm. While being inside that JForm, I call another JForm. Think of it as a multiple step registration process. When I'm inside the second form, will the previously created thread still be inside the run()? Or is the new JForm creating a new thread? I want to keep the first thread alive and access a shared resource through out the lifetime of it.
class Form1 extends JForm{
public void jButton1ActionPerformed(..){
///show Form2
}
}
class A extends Thread{
public void run() {
//show Form1
}
}
class Main {
public static void main(String args[]){
new A().start();
new A().start();
new A().start();
}
Thanks.
When you create and run your A thread, you will simply show the Form and continue executing that Thread. Separately, on the single, dedicated Swing Thread (started automatically for you) the users click will be caught and handled, resulting in a call to jButton1ActionPerformed. That code block will execute inside the Swing thread.
Hope that helps. Note that you can name your threads and always use Thread.currentThread().getName() to help you understand further what is going on in your code.
If you want to create and show a Swing component from within a non-EDT thread, you must place the Swing code in a Runnable and queue it on the event thread like so:
class A extends Thread{
public void run() {
//show Form1
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Form1 form1 = new Form1();
form1.setVisible(true);
}
});
}
}
So regardless of how many "A" objects you create, and thus separate new threads you create, all Swing code will be running on the same one thread.
As an addition to my current application, I need to create a separate thread which will periodically do some processing
I've create a new class to do all this, and this class will be loaded on startup of my application.
This is what I have so far :
public class PeriodicChecker extends Thread
{
static
{
Thread t = new Thread(new PeriodicChecker());
while(true)
{
t.run();
try
{
Thread.sleep(5000l);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
/**
* Private constructor to prevent instantiation
*/
private PeriodicChecker()
{
}
#Override
public void run()
{
System.out.println("Thread is doing something");
// Actual business logic here, that is repeated
}
}
I want to make constructor private to prevent other people from attempting to instantiate this class accidentally. How can I achieve this?
Also, is there anything bad about my implementation of such requirements? I'm only creating one thread which will run then sleep, have I missed anything obvious? I haven't worked with threads before
Java offers ScheduledExecutorService to schedule and run periodic tasks or tasks with delay. It should provide all the features you need. Timer is another class that offers similar functionalities, but I would recommend the ScheduledExecutorService over Timer for its flexibility of configuration and better error management.
You have some conceptual erros in your code... for example:
You should call start() and not run(), because you are running the method sequentially and not simultaneously.
You can call start() only once, not once in each loop iteration. After that, the thread is in state TERMINATED, you should create a new thread to run it again
You should not create the thread in the static block, it is a bad practice, and maybe the Thread is running before you want it to run.
You should read some examples about thread, it is a little difficult to unserstand at the beginning, and you can have undesired effects very easily.
Here is a little example, that may do something similar to that you want:
public class PeriodicChecker extends Thread
{
#Override
public void run()
{
while(true) {
System.out.println("Thread is doing something");
Thread.sleep(5000);
}
}
}
public OtherClass {
public static void main(String args[]) {
Thread t = new PeriodicChecker();
t.start();
}
}
If you want that none can create a new Thread, you could create a singleton, so you will be sure that none is creating more threads.
I'd recommend you to consider Timer class - it provides functionality for periodic tasks execution.
Also you may take a look at "Timer & TimerTask versus Thread + sleep in Java" question discussion - there you can find some arguments and examples.
First of all to answer your specific question, you have already achieved your objective. You have declared your constructor to be private meaning no external class can call it like new PeriodicChecker().
Looking at your code however, there are a number of other problems:
Firstly, you are creating an instance of your class within its own static constructor. The purpose of a static constructor is to initialise any static state that your class may have, which instances of your class may then depend on. By creating an instance of the class within the static constructor, all of these guarantees go out the window.
Secondly, I don't think your thread is going to behave in the way you expect it to behave, primarily because you don't actually start another thread :). If you intend to start a new thread, you need to call the start() method on that thread object. Calling run() as you do does not actually create a new thread, but simply runs the run() method in the current thread.
Nowadays when you want to create a new thread to do something, the reccomended way of achieving this is to not extend Thread, but instead implement the Runnable interface. This allows you to decouple the mechanism of the thread, from the behaviour you intend to run.
Based on your requirements, I would suggest doing away with a top-level class like this, and instead create either a private inner class within your application start-up code, or even go for an anonymous inner class:
public class Main {
public static void main(String[] args) {
new Thread(new Runnable() {
#Override
public void run() {
while(true) {
System.out.println("Thread is doing something");
Thread.sleep(5000);
}
}
}).start();
}
}
It is almost never right to extend Thread. If you ever find yourself doing this, step back, take a look and ask yourself if you really need to change the way the Thread class works.
Almost all occurances where I see extends Thread the job would be better done implementing the Runnable interface or using some form of Timer.