【问题标题】:Execute only one instance of SwingWorker只执行一个 SwingWorker 实例
【发布时间】:2014-07-16 12:56:52
【问题描述】:

假设我有一个 Java GUI,它在面板中显示来自选定区域的 40 个批处理对象,这些对象可以从 A 到 Z。

这 40 个 Batch 对象是从数据库中查询出来的,数据库按区域缓存它们,这样对区域的每个请求就不会每次都涉及数据库。

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;
  }
}

假设缓存通过一系列通知正确更新,并且每次 drawIt() 方法正确更新时,我怎样才能使 BuildBatchSwingWorker 不会为同一区域同时调用多次?

【问题讨论】:

  • 但在那种情况下,我认为你应该稍后用户调用我的意思是 swingutilities,因为它不会让用户在执行当前线程之前启动任何其他线程
  • 嘿,你成功了.. 使用 invokeLater 我可以多次调用 Runnable 但这些将按顺序执行,第二个将利用前一个的缓存。你能发布一些更详细的东西让我接受吗?
  • 看我更新了一个例子:)

标签: java swing concurrency swingworker


【解决方案1】:

鉴于您的代码,我认为您真正关心的不是SwingWorker 执行多少次,而是只调用一次数据库,然后使用BatchDAO 的缓存。

你需要适当地分离职责,缓存维护是BatchDAO类的工作,因此swing worker与它无关:

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;
    }
    ...
}

然后在你的 GUI 类(它所属的地方)中执行一个 swing worker:

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();
    }

}

请注意,如果cache.get("batch-" + zone) == null 则数据库调用将只执行一次,但如果不是,那么您将使用您的 chache 并且doInBackground() 方法将在眨眼间执行,我认为这是您的目标。


题外话

由于我在 BatchView 类的构造函数中看到 Graphics 对象作为参数,我建议您仔细阅读 Performing Custom Painting 教程以避免自定义绘制不希望出现的问题(如果您还没有阅读它但是,当然)。

【讨论】:

    【解决方案2】:

    这是你可以调用的 Swing 实用程序的一个很好的例子 :)

        /*
         * 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
        }
    

    【讨论】:

    • “这是你可以调用的 Swing 实用程序的一个很好的例子”Event Dispatch Thread 的上下文中调用Thread.sleep() 绝不是一个好主意,因为它将阻止此线程使您的 GUI 无响应。此外,您的示例除了阻止 EDT 之外什么也不做。因此,尽管您付出了努力,但我担心它根本无法回答这个问题,而且这是一个糟糕的建议。
    • 问题是,根据他们的要求,他们只需要线程一个实例,所以在这种情况下,我认为这样会很好。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-05-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-11
    相关资源
    最近更新 更多