zoukankan      html  css  js  c++  java
  • Swing中的线程并发处理

    理论解释见官方的文档:

    https://docs.oracle.com/javase/tutorial/uiswing/concurrency/index.html

    一个Swing程序中一般有下面三种类型的线程:

    •     初始化线程(Initial Thread)
    •     UI事件调度线程(EDT)
    •     任务线程(Worker Thread),可以看成后台其他的线程

            每个程序必须有一个main方法,这是程序的入口。该方法运行在初始化或启动线程上。初始化线程读取程序参数并初始化一些对象。在许多Swing程序中,该线程主要目的是启动程序的图形用户界面(GUI)。一旦GUI启动后,对于大多数事件驱动的桌面程序来说,初始化线程的工作就结束了。
            Swing程序只有一个EDT线程,该线程负责GUI组件的绘制和更新,通过调用程序的事件处理器来响应用户交互。所有事件处理都是在EDT上进行的,程序同UI组件和其基本数据模型的交互只允许在EDT上进行,所有运行在EDT上的任务应该尽快完成,以便UI能及时响应用户输入。
            Swing编程时应该注意以下两点:
    1.从其他线程访问UI组件及其事件处理器会导致界面更新和绘制错误。
    2.在EDT上执行耗时任务会使程序失去响应,这会使GUI事件阻塞在队列中得不到处理。
    3.应使用独立的任务线程来执行耗时计算或输入输出密集型任务,比如同数据库通信、访问网站资源、读写大树据量的文件。

      从java6开始,SwingWorker类帮你管理任务线程和Swing EDT之间的交互,对于任务线程来说,就是SwingWorker执行和界面无直接关系的耗时任务和I/O密集型操作

    一个主界面启动的正确姿势:

        public static void main(String[] args) {
    
            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    MainFrame mainUI = new MainFrame();
                    mainUI.showJFrame();
                }
            });
    
        }

      将任务放到EDT执行的方法是SwingUtilities.invokeAndWait,不像invokeLater,invokeAndWait方法是阻塞执行的,它在EDT上执行Runnnable任务,直到任务执行完了,该方法才返回调用线程。
      invokeLater和invokeAndWait都在事件派发队列中的所有事件都处理完之后才执行它们的Runnable任务,也就是说,这两个方法将Runnable任务放在事件队列的末尾。
      注意:虽然可以在其他线程上调用invokeLater,也可以在EDT上调用invokeLater,但是千万不要在EDT线程上调用invokeAndWait方法!这样做会造成线程竞争,程序就会陷入死锁。那么一个好的办法是不要使用invokeAndWait方法。

    一个演示阻塞和非阻塞的例子:

    Factorial,用于普通阶乘计算类

    package concurrency;
    
    public class Factorial {
    
        private int n;
         
        public Factorial(int n) {
            this.n = n;
        }
     
        public Integer call() {
            int result = 1;
     
            for (int i = 1; i <= n; i++) {
                result = result * i;
            }
     
            try {
                Thread.sleep(5000);
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }
            
            System.out.println("currentThread = " + Thread.currentThread().getName());
            return result;
        }
    
    }

    一个Callable的阶乘实现类

    package concurrency;
    
    import java.util.concurrent.Callable;
    
    public class FactorialCalculator implements Callable<Integer> {
        private int n;
     
        public FactorialCalculator(int n) {
            this.n = n;
        }
     
        public Integer call() {
            int result = 1;
     
            for (int i = 1; i <= n; i++) {
                result = result * i;
            }
     
            try {
                Thread.sleep(5000);
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }
     
            System.out.println("currentThread = " + Thread.currentThread().getName());
            return result;
        }
    }

    测试类

    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.Future;
    import java.util.concurrent.FutureTask;
    
    import javax.swing.JButton;
    import javax.swing.SwingWorker;
    
    import concurrency.Factorial;
    import concurrency.FactorialCalculator;
    
    public class DoBackground {
    
        public DoBackground() {
            // TODO Auto-generated constructor stub
        }
        
        //线程池处理,阻塞主UI
        public static void blockFutureGet() {
            ExecutorService pool = Executors.newSingleThreadExecutor();
            Future<Integer> factorialResult = pool.submit(new FactorialCalculator(8));
            try {
                // Integer factorialValue = factorialResult.get(3,
                // TimeUnit.SECONDS);
                Integer factorialValue = factorialResult.get();
                System.out.println("Factorial Value (用FutureGet处理) = " + factorialValue);
    
            } catch (InterruptedException | ExecutionException ex) {
                ex.printStackTrace();
            }
    
            pool.shutdown();
        }
        
        //线程池futureTask处理,演示组塞主UI
        public static void blockFutureTaskGet() {
            ExecutorService pool = Executors.newSingleThreadExecutor();
            
            FactorialCalculator task = new FactorialCalculator(8);
            FutureTask<Integer> futureTask = new FutureTask<Integer>(task);
            
            pool.submit(futureTask);
            pool.shutdown();
            try {
                Integer factorialValue = futureTask.get();
                System.out.println("Factorial Value (用FutureTaskGet处理) = " + factorialValue);
    
            } catch (InterruptedException | ExecutionException ex) {
                ex.printStackTrace();
            }
    
            
        }
        
        //用主线程处理,阻塞
        public static void blockMainThread() {
            Factorial cal = new Factorial(8);
            System.out.println("Factorial Value (用主线程处理) = " + cal.call());
        }
    
        //用FutureGet + swingwork处理
        public static void swingworkConcurrency() {
            final SwingWorker worker = new SwingWorker() {
    
                @Override
                protected Object doInBackground() throws Exception {
                    // TODO Auto-generated method stub
                    ExecutorService pool = Executors.newSingleThreadExecutor();
                    Future<Integer> factorialResult = pool.submit(new FactorialCalculator(8));
                    try {
                        // Integer factorialValue = factorialResult.get(3,
                        // TimeUnit.SECONDS);
                        Integer factorialValue = factorialResult.get();
                        System.out.println("Factorial Value (用FutureGet + swingwork处理)  = " + factorialValue);
    
                    } catch (InterruptedException | ExecutionException ex) {
                        ex.printStackTrace();
                    }
    
                    pool.shutdown();
                    return null;
                }
    
            };
            worker.execute();
        }
    
        //用swingwork线程处理
        public static void swingworkMainThread() {
            final SwingWorker worker = new SwingWorker() {
    
                @Override
                protected Object doInBackground() throws Exception {
                    try {
                        Factorial cal = new Factorial(8);
                        System.out.println("Factorial Value (用swingwork线程处理) = " + cal.call());
    
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }
                    return null;
                }
    
            };
            worker.execute();
        }
        
        /**
         * 用swingwork分发线程处理回调,并读写外部的变量值
         * @param jbtn,SwingWorker外部的对象
         */
        public static void swingworkCallback(JButton jbtn) {
            
            Integer backInteger;
            
            SwingWorker<Integer, Object> worker = new SwingWorker<Integer, Object>() {
    
                @Override
                protected Integer doInBackground() throws Exception {
                    try {
                        Factorial cal = new Factorial(8);
                        
                        return cal.call();
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }
                    return null;
                }
                
                @Override
                public void done() {
                    try {
                        System.out.println("Factorial Value (用swingwork分发线程处理回调) = " + get());
                        //backInteger = (Integer) get();
                        setTitle(jbtn,get().toString());
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    } catch (ExecutionException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
    
            };
            worker.execute();
        }
        
        static void setTitle(JButton jbtn,String text){
            
            jbtn.setText(text);
        }
    
        
    }

    结论:用后两种方法就已经能够实现非阻塞的设计了,即没必要自己再新建线程,或开线程池,请把一切交给swingwork去处理。

    最后一个例子演示了回调如何和swing的其他对象(比如说一个jbutton进行数据读写,这是跨线程的操作,swingwork也支持的非常好)。

    运行结果:

  • 相关阅读:
    平分糖果——BZOJ 1045
    浙大月赛——ZOJ Problem Set 3574
    jsp 自定义标签的写法
    C#扩展方法(转贴)
    window mobile 防止系统休眠代码
    jbpm sql使用动态参数方法
    spring 多数据源配置实现
    原创jquery蒙版控件
    jbpm 错误解决方法
    cas server 配置
  • 原文地址:https://www.cnblogs.com/starcrm/p/6972561.html
Copyright © 2011-2022 走看看