2

I am creating 4 threads and each thread is associated with a UI. The UI performs a long running task, for that I have used a SwingWorker. But the problem that arises is instead of running as a multithreaded app, it is running in queue.

Interesting to note that when I remove the SwingWorker it behaves and runs as multithreaded.

My code is as:

NewClass

package thread;

public class NewClass
{
    public static void main(String[] args) throws Exception
    {
        for(int i=0; i<4 ; i++)
        {
            new ThreadFront().startsThread();
            Thread.sleep(2000);
        } 
    }
}

class ThreadFront implements Runnable
{
    private Thread t;

    public ThreadFront() 
    {
        t = new Thread(this, "");

    }

    public void startsThread()
    {
        t.start();
    }

    @Override
    public void run()
    {
        try
        {
            UI ui = new UI();
            ui.startThread();
        }
        catch(Exception ae)
        {
            ae.printStackTrace();
        }
    }
}

UI class

package thread;

import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.SwingWorker;

public class UI extends javax.swing.JFrame
{
    public UI()
    {
        initComponents();    
        setVisible(true); 
    }

    public void startThread() throws Exception
    {       
        new SwingWorker<Integer, Integer>()
        {
            @Override
            protected Integer doInBackground() throws Exception 
            {                
                for(int i=0; i<10;i++)
                {
                    jTextArea1.append(""+i);
                    Thread.sleep(3000);
                }
                return 0;
            }

            @Override
            protected void process(List<Integer> chunks) 
            {
                for(Integer message : chunks)
                {
                    jProgressBar1.setValue(message); 
                    jProgressBar1.repaint();
                }
            }

            @Override
            protected void done() 
            {
                try 
                {
                    get();
                }
                catch(final Exception ex) 
                {
                    ex.printStackTrace();
                }
            }
        }.execute();
    }

    // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
    private void initComponents() {

        jPanel1 = new javax.swing.JPanel();
        jPanel2 = new javax.swing.JPanel();
        jLabel1 = new javax.swing.JLabel();
        jPanel3 = new javax.swing.JPanel();
        jScrollPane1 = new javax.swing.JScrollPane();
        jTextArea1 = new javax.swing.JTextArea();
        jLabel2 = new javax.swing.JLabel();
        jobid_field = new javax.swing.JLabel();
        jProgressBar1 = new javax.swing.JProgressBar();
        work_field = new javax.swing.JLabel();
        jLabel4 = new javax.swing.JLabel();
        jLabel3 = new javax.swing.JLabel();
        session_field = new javax.swing.JLabel();

        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
        setLocationByPlatform(true);
        setResizable(false);
        addWindowListener(new java.awt.event.WindowAdapter() {
            public void windowClosing(java.awt.event.WindowEvent evt) {
                formWindowClosing(evt);
            }
        });

        jPanel1.setLayout(new java.awt.BorderLayout());

        jPanel2.setBackground(new java.awt.Color(204, 204, 204));
        jPanel2.setBorder(javax.swing.BorderFactory.createMatteBorder(1, 1, 1, 1, new java.awt.Color(255, 255, 255)));
        jPanel2.setForeground(new java.awt.Color(204, 204, 204));

        jLabel1.setFont(new java.awt.Font("Century Gothic", 1, 14)); // NOI18N
        jLabel1.setText("iZoneX Math Process");

        javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2);
        jPanel2.setLayout(jPanel2Layout);
        jPanel2Layout.setHorizontalGroup(
            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel2Layout.createSequentialGroup()
                .addGap(18, 18, 18)
                .addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 304, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(86, Short.MAX_VALUE))
        );
        jPanel2Layout.setVerticalGroup(
            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel2Layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jLabel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addContainerGap())
        );

        jPanel1.add(jPanel2, java.awt.BorderLayout.NORTH);

        jPanel3.setBackground(new java.awt.Color(204, 204, 204));
        jPanel3.setBorder(javax.swing.BorderFactory.createMatteBorder(1, 1, 1, 1, new java.awt.Color(255, 255, 255)));

        jTextArea1.setEditable(false);
        jTextArea1.setBackground(new java.awt.Color(255, 255, 204));
        jTextArea1.setColumns(20);
        jTextArea1.setFont(new java.awt.Font("Century Gothic", 1, 12)); // NOI18N
        jTextArea1.setForeground(new java.awt.Color(255, 0, 0));
        jTextArea1.setLineWrap(true);
        jTextArea1.setRows(5);
        jTextArea1.setWrapStyleWord(true);
        jScrollPane1.setViewportView(jTextArea1);

        jLabel2.setText("Job ID. :");

        jLabel4.setText("Processing: ");

        jLabel3.setText("Session ID: ");

        javax.swing.GroupLayout jPanel3Layout = new javax.swing.GroupLayout(jPanel3);
        jPanel3.setLayout(jPanel3Layout);
        jPanel3Layout.setHorizontalGroup(
            jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel3Layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                    .addComponent(jScrollPane1, javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(javax.swing.GroupLayout.Alignment.LEADING, jPanel3Layout.createSequentialGroup()
                        .addComponent(jLabel2)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(jobid_field, javax.swing.GroupLayout.PREFERRED_SIZE, 115, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addGap(33, 33, 33)
                        .addComponent(jLabel3)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(session_field, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                    .addComponent(jProgressBar1, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addGroup(jPanel3Layout.createSequentialGroup()
                        .addComponent(jLabel4, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addComponent(work_field, javax.swing.GroupLayout.PREFERRED_SIZE, 320, javax.swing.GroupLayout.PREFERRED_SIZE)))
                .addContainerGap())
        );
        jPanel3Layout.setVerticalGroup(
            jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel3Layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
                    .addComponent(jLabel2, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(jobid_field, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(jLabel3)
                    .addComponent(session_field, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 148, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(jProgressBar1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(work_field, javax.swing.GroupLayout.PREFERRED_SIZE, 22, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(jLabel4, javax.swing.GroupLayout.PREFERRED_SIZE, 18, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addContainerGap())
        );

        jPanel1.add(jPanel3, java.awt.BorderLayout.CENTER);

        getContentPane().add(jPanel1, java.awt.BorderLayout.CENTER);

        pack();
    }// </editor-fold>                        

    private void formWindowClosing(java.awt.event.WindowEvent evt) {                                   

    }                                  

    // Variables declaration - do not modify                     
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel3;
    private javax.swing.JLabel jLabel4;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JPanel jPanel2;
    private javax.swing.JPanel jPanel3;
    private javax.swing.JProgressBar jProgressBar1;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JTextArea jTextArea1;
    private javax.swing.JLabel jobid_field;
    private javax.swing.JLabel session_field;
    private javax.swing.JLabel work_field;
    // End of variables declaration                   

}

What would be the alternative to worker Threads in Swing in that case?

Ralf de Kleine
  • 11,464
  • 5
  • 45
  • 87
Tech Enthusiast
  • 279
  • 1
  • 5
  • 18

1 Answers1

4

Um, no, this is not how multithreading works in Swing.

There is a single UI thread (known as the Event Dispatching Thread), all updates and interactions with the UI are expected to be done from within the context of the EDT, so doing things like...

@Override
public void run()
{
    try
    {
        UI ui = new UI();
        ui.startThread();
    }
    catch(Exception ae)
    {
        ae.printStackTrace();
    }
}

And...

@Override
protected Integer doInBackground() throws Exception 
{                
    for(int i=0; i<10;i++)
    {
        jTextArea1.append(""+i);
        Thread.sleep(3000);
    }
    return 0;
}

Are actually breaking this rule.

Instead, each UI should have its own SwingWorker (as it does now), but should be created from within the context of the EDT.

Each SwingWorker should be calling publish in order to push the results of the doInBackground method back to the EDT.

SwingWorker has its own progress support via the PropertyChange support

For example...

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class MultiThreadedUI {

    public static void main(String[] args) {
        new MultiThreadedUI();
    }

    public MultiThreadedUI() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                final List<TestPane> panes = new ArrayList<>(5);
                for (int index = 0; index < 5; index++) {
                    panes.add(new TestPane(Integer.toString(index)));
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new GridLayout(0, 1));
                for (TestPane pane : panes) {
                    frame.add(pane);
                }
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);

                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        for (TestPane pane : panes) {
                            pane.makeItSo();
                        }
                    }
                });
            }
        });
    }

    public class TestPane extends JPanel {

        private JTextArea textArea;
        private JProgressBar pb;
        private String name;

        public TestPane(String name) {
            this.name = name;
            textArea = new JTextArea(10, 5);
            pb = new JProgressBar();
            setLayout(new BorderLayout());
            add(new JScrollPane(textArea));
            add(pb, BorderLayout.SOUTH);
        }

        public void makeItSo() {

            BackgroundWorker worker = new BackgroundWorker();
            worker.addPropertyChangeListener(new PropertyChangeListener() {
                @Override
                public void propertyChange(PropertyChangeEvent evt) {
                    if ("progress".equalsIgnoreCase(evt.getPropertyName())) {
                        pb.setValue((Integer)evt.getNewValue());
                    }
                }
            });
            worker.execute();

        }

        protected class BackgroundWorker extends SwingWorker<Integer, Integer> {

            @Override
            protected void process(List<Integer> chunks) {
                for (Integer value : chunks) {
                    textArea.append(name + ": " + value + "\n");
                }
            }

            @Override
            protected Integer doInBackground() throws Exception {
                int delay = (int)(Math.random() * 3000);
                for (int i = 0; i < 10; i++) {
                    publish(i);
                    setProgress((int) (Math.round(((double) i / (double) 9) * 100)));
                    Thread.sleep(delay);
                }
                return 0;
            }

        }

    }

}
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • The Requirement is for multiple and separate SwingWorker Threads each allotted for its own process and updating the UI simultaneously. – Tech Enthusiast Dec 23 '13 at 09:44
  • Yep, this is exactly what the example does. What you can't do is update the UI from outside the Event Dispatching Thread – MadProgrammer Dec 23 '13 at 09:46
  • Your example is exactly doing what i am explaining in my example.Each worker thread only updates its parent UI at single Time and blocks others workers.Other runs only when the first completes. – Tech Enthusiast Dec 23 '13 at 09:54
  • Okay, the problem is. That's the way it works. Swing is a single threaded framework. All interactions and modifications to the ui MUST be made from within the context of the EDT. While each `SwingWorker` executes independently, when the UI is updated, all the updates are synced back to the EDT. This is how it works and there is no other way to do it. Anything else will lead to at best, strange graphics artifacts and out of sync updates and at worse thread deadlocks. – MadProgrammer Dec 23 '13 at 09:58