0

Suppose I have a Java GUI which shows in a panel 40 Batch objects from a selected zone which can go from A to Z.

The 40 Batch objects are queried from database which caches them by zone so that each request for a zone doesn't involve the database every time.

public class BatchView
{

  private int drawIt(Graphics g, String zone)
  {
     for(int i = 0; i<40; i++)
       {
          Batch tmpBatch = BatchDAO.getBatch(zone, i);
          //draw the tmpBatch object
       }
  }
}

public class BatchDAO 
{
  public static MyCache cache = new MyCache(5000);

  public getAllBatches(String zone)
  {
    ArrayList<Batch> batchArrayList = cache.get("batch-" + zone);
    if(batchArrayList == null)
    {
        BuildBatchSwingWorker buildBatchSwingWorker = new BuildBatchSwingWorker(zone);
        buildBatchSwingWorker.execute();
    }
    return batchList;
  }

  public Batch getBatch(String zone, int id)
  {
     //here I don't query database but exploit the cache
     ArrayList<Batch> batchArrayList = getAllBatches(String zone);
     for(int i = 0; i< batchArrayList.size(); i++)
     {
       if(batchArrayList.get(i).getId() == i)
            return batchArrayList.get(i);
     }
     //if batch is not found it means it hasn't loaded yet so I return null
     return null;
  }
}

Suppose the cache is correcly updated with a series of notifications and each time the drawIt() method correctly updates, how can I make it so that BuildBatchSwingWorker is not called multiple times concurrently for the same zone?

mKorbel
  • 109,525
  • 20
  • 134
  • 319
dendini
  • 3,842
  • 9
  • 37
  • 74
  • but in that case i think u should user invokelater i mean swingutilities because it wont let user to start any other thread before it execute current one – Kishan Bheemajiyani Jul 16 '14 at 13:46
  • Hey you nailed it.. with invokeLater I can call multiple time the Runnable but these will be executed sequentially and the second one will exploit the cache of the previous one. Can you post something more elaborate so I can accept it? – dendini Jul 16 '14 at 14:35
  • see i have updated one example :) – Kishan Bheemajiyani Jul 17 '14 at 05:12

2 Answers2

1

Given your code I think that what really concerns you is not how many times SwingWorker executes but do database call just once and then use BatchDAO's cache.

You need to separate responsibilities properly, cache maintenace is a job for BatchDAO class and thus swing worker has nothing to do with it:

public class BatchDAO {
    ...
    public getAllBatches(String zone) {
        ArrayList<Batch> batchArrayList = cache.get("batch-" + zone);
        if(batchArrayList == null) {
            // here goes database call not swing worker!
        }
        return batchList;
    }
    ...
}

Then execute a swing worker in your GUI class (where it belongs):

public class BatchView {

    private int drawIt(Graphics g, String zone) {
        SwingWorker<Void, Batch> worker = new SwingWorker<Void, Batch>() {
            @Override
            protected Void doInBackground() throws Exception {
                for(int i = 0; i<40; i++) {
                    Batch tmpBatch = BatchDAO.getBatch(zone, i);
                    publish(tmpBatch);
                 }
                 return null;
             }

             @Override
             protected void process(List<Batch> batches) {
                 for(Batch batch : batches) {
                     //draw the batch object
                 }
             }
         };

         worker.execute();
    }

}

Note if cache.get("batch-" + zone) == null then database call would be performed only once, but if not then you will be using your chache and doInBackground() method would be executed in a blink of an eye, which I think is your goal.


Off-topic

Since I see a Graphics object as parameter in your BatchView class' constructor, I'd suggest you take a close read to Performing Custom Painting tutorial to avoid custom painting undesired issues (if you haven't read it yet, of course).

dic19
  • 17,821
  • 6
  • 40
  • 69
0

Here this is good example of Swing utilities that u can call :)

    /*
     * To change this template, choose Tools | Templates
     * and open the template in the editor.

    package com.verve.swinguti;

    import javax.swing.SwingUtilities;

    /**
     *
     * @author kishan
     */
    public class Utilities extends javax.swing.JFrame {

        /**
         * Creates new form Utilities
         */
        public Utilities() {
            initComponents();
        }

        /**
         * This method is called from within the constructor to initialize the form.
         * WARNING: Do NOT modify this code. The content of this method is always
         * regenerated by the Form Editor.
         */
        @SuppressWarnings("unchecked")
        // <editor-fold defaultstate="collapsed" desc="Generated Code">
        private void initComponents() {

            jPanel1 = new javax.swing.JPanel();
            jButton2 = new javax.swing.JButton();
            jButton1 = new javax.swing.JButton();

            setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

            jButton2.setText("jButton2");
            jButton2.addActionListener(new java.awt.event.ActionListener() {
                public void actionPerformed(java.awt.event.ActionEvent evt) {
                    jButton2ActionPerformed(evt);
                }
            });

            javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
            jPanel1.setLayout(jPanel1Layout);
            jPanel1Layout.setHorizontalGroup(
                jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(jPanel1Layout.createSequentialGroup()
                    .addGap(71, 71, 71)
                    .addComponent(jButton2)
                    .addContainerGap(155, Short.MAX_VALUE))
            );
            jPanel1Layout.setVerticalGroup(
                jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(jPanel1Layout.createSequentialGroup()
                    .addGap(118, 118, 118)
                    .addComponent(jButton2)
                    .addContainerGap(128, Short.MAX_VALUE))
            );

            jButton1.setText("jButton1");
            jButton1.addActionListener(new java.awt.event.ActionListener() {
                public void actionPerformed(java.awt.event.ActionEvent evt) {
                    jButton1ActionPerformed(evt);
                }
            });

            javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
            getContentPane().setLayout(layout);
            layout.setHorizontalGroup(
                layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(layout.createSequentialGroup()
                    .addContainerGap()
                    .addComponent(jButton1)
                    .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                    .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addContainerGap())
            );
            layout.setVerticalGroup(
                layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(layout.createSequentialGroup()
                    .addContainerGap()
                    .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                        .addGroup(layout.createSequentialGroup()
                            .addComponent(jButton1)
                            .addGap(0, 0, Short.MAX_VALUE))
                        .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                    .addContainerGap())
            );

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

        private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
            // TODO add your handling code here:
            try {
                SwingUtilities.invokeLater(new Runnable() {

                    @Override
                    public void run() {
                        try {
                            for (int i = 0; i < 10; i++) {
                                System.out.println("This is Good Example**");
                                Thread.sleep(2000);
                            }

                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                });

            } catch (Exception e) {
                e.printStackTrace();
            }

        }

        private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {
            // TODO add your handling code here:
            try {
                System.out.println("This is Second Button");

            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        /**
         * @param args the command line arguments
         */
        public static void main(String args[]) {
            /*
             * Set the Nimbus look and feel
             */
            //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
            /*
             * If Nimbus (introduced in Java SE 6) is not available, stay with the
             * default look and feel. For details see
             * http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
             */
            try {
                for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                    if ("Nimbus".equals(info.getName())) {
                        javax.swing.UIManager.setLookAndFeel(info.getClassName());
                        break;
                    }
                }
            } catch (ClassNotFoundException ex) {
                java.util.logging.Logger.getLogger(Utilities.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
            } catch (InstantiationException ex) {
                java.util.logging.Logger.getLogger(Utilities.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
            } catch (IllegalAccessException ex) {
                java.util.logging.Logger.getLogger(Utilities.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
            } catch (javax.swing.UnsupportedLookAndFeelException ex) {
                java.util.logging.Logger.getLogger(Utilities.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
            }
            //</editor-fold>

            /*
             * Create and display the form
             */
            java.awt.EventQueue.invokeLater(new Runnable() {

                public void run() {
                    new Utilities().setVisible(true);
                }
            });
        }
        // Variables declaration - do not modify
        private javax.swing.JButton jButton1;
        private javax.swing.JButton jButton2;
        private javax.swing.JPanel jPanel1;
        // End of variables declaration
    }

See this click button1 and u wont be able to click other button till it completes process of button1

Kishan Bheemajiyani
  • 3,429
  • 5
  • 34
  • 68
  • *"Here this is good example of Swing utilities that u can call"* It is never a good idea call `Thread.sleep()` in the context of the [Event Dispatch Thread](http://docs.oracle.com/javase/tutorial/uiswing/concurrency/dispatch.html) just because it will block this thread making your GUI unresponsive. Also, your example does nothing but block the EDT. Therefore, despite your effort, I'm affraid it doesn't answer the question at all plus it's a poor advice. – dic19 Jul 17 '14 at 12:39
  • the thing is that according to their requirement they want the thread one instance only so in that case it will be good okey i think so. – Kishan Bheemajiyani Jul 17 '14 at 12:47