posted on: 2011-06-19 23:33:06
Takes a look at the currently generated code, isolates some problems and uses some built in features to create the features that we want. Namely a single threaded program with a GUI front-end.

>PREVIOUS

For starters look at the current code

public class SimpleFrame {

    public static void main(String[] args){
        JFrame frame = new JFrame("threaded application");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(400,400);

        final JLabel label = new JLabel("display");

        final JButton button = new JButton("name");

        button.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent event){
                Runnable r = new Runnable(){
                    public void run(){
                        label.setText(Thread.currentThread().getName());
                        try{

                            Thread.sleep(500);

                        } catch(InterruptedException e){
                           //not to worry.
                        }
                    }
                };
                new Thread(r).start();
            }
        });

        JPanel content = new JPanel();
        content.add(label);

        content.add(button);

        frame.setContentPane(content);
        frame.setVisible(true);
    }

}

Two immediate problems are a) Many threads are being created and ran in parallel, which makes our application not 'single threaded,' and b) Swing modifications are being performed off of the EDT.

Ouch, so we spent our time trying to get an action off of the EDT, and now that it is off of the edit ... we want to get back onto it? This is easy, there is a convenience method:

EventQueue.invokeLater(Runnable r)

A great resource for this is actually a class called the SwingWorker. I am not going to use this class, but the documentation is great. It gives us a rule of thumb:

"

When writing a multi-threaded application using Swing, there are two constraints to keep in mind:

*Time-consuming tasks should not be run on the Event Dispatch Thread. Otherwise the application becomes unresponsive.

*Swing components should be accessed on the Event Dispatch Thread only.

"

I want to use an ExecutorService instead. These are very simple to get started, once you know what you are looking for.

ExecutorService pool = Executors.newFixedThreadPool(1);

Then any time we want to execute a task we just submit it. So now we have a complete program that runs a single threaded program with a GUI front end. I've included the import statements if you actually want to run this.

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


public class SimpleFrame {

    public static void main(String[] args){
        JFrame frame = new JFrame("threaded application");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(400,400);

        final JLabel label = new JLabel("display");

        final JButton button = new JButton("name");
        final ExecutorService pool = Executors.newFixedThreadPool(1);

        button.addActionListener(new ActionListener(){
            int counter = 0;
            public void actionPerformed(ActionEvent event){
                counter++;
                final int count = counter;
                
                Runnable r = new Runnable(){
                    public void run(){
                        postOnEventQueue(count + " " + Thread.currentThread().getName(), label);
                        try{
                            Thread.sleep(500);
                        } catch(InterruptedException e){
                           //not to worry.
                        }
                    }
                };
                pool.submit(r);
            }
        });

        JPanel content = new JPanel();
        content.add(label);

        content.add(button);

        frame.setContentPane(content);
        frame.setVisible(true);
    }
    /* Changes the text of label l to string s, on the event queue or edt*/
    public static void postOnEventQueue(String s, JLabel l){
        final String fs = s;
        final JLabel fl = l;
        EventQueue.invokeLater(new Runnable(){
           public void run(){
               fl.setText(fs);
           }
        });
    }

}

Notice that when you click the button it responds immediately, and if you click the button numerous times, it wait at least half a second to update the text.

Comments

None
2014-04-30 12:16:07
None
Name: