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也支持的非常好)。

    运行结果:

  • 相关阅读:
    git常用指令 github版本回退 reset
    三门问题 概率论
    如何高效的学习高等数学
    数据库6 关系代数(relational algebra) 函数依赖(functional dependency)
    数据库5 索引 动态哈希(Dynamic Hashing)
    数据库4 3层结构(Three Level Architecture) DBA DML DDL DCL DQL
    梦想开始的地方
    java String字符串转对象实体类
    java 生成图片验证码
    java 对象之间相同属性进行赋值
  • 原文地址:https://www.cnblogs.com/starcrm/p/6972561.html
Copyright © 2011-2022 走看看