我们知道Swing不是线程安全的。意思是只能在事件处理线程里更改图形界面元素。如果在其他线程里更改,有可能会出问题。为什么不把Swing设计成线程安全的呢?很多牛人都说不容易。由于事件处理线程负责处理事件和画图形界面,所以不能在事件处理线程了做非常耗时的任务。不然图形界面有可能卡。可以让事件处理线程休眠测试一下。解决办法是把耗时的事件放在另一个线程里。现在我需要休眠一下之后然后更改图形界面,一直循环。该怎么办

解决方案 »

  1.   

    调整你的系统需求。任何情况下,你都没有理由去把GUI事件线程给休眠了你可以设置标志、状态等方式,将某些功能屏蔽、禁用啥的,但没道理去 Stop The World
      

  2.   

    并不复杂,GUI线程啥都别管,就是初始化完毕后,顺手启动下负责动画的线程,比如叫AnimationWorker。伪代码类似如下:public class AnimationWorker {private Image imgAnimation;private Container main; public AnimationWorker (Container main) {
      this.main = main; // 负责显示动画的容器
    }public void run() {
      while(runFlag) {
        // 处理动画生成等工作
        // 然后将生成好的图片设置到 imgAnimation 中
        main.repaint(); // 发送repaint事件给GUI线程,GUI线程空闲了就会执行刷新
        Thread.sleep(1000);
      }
    }public Image getAnimation() { // 供GUI线程在刷新是,获取最新的动画图片。
      return imgAnimation;
    }
    }
      

  3.   

    这几天也正在为 swing 线程 纠结, 不过还好都解决了, 知道为什么?建议LZ 去看一下 《java 多线程设计模式》 这本书,看完了你就明白你的问题有多简单了
      

  4.   

    你也说了可以把耗时的放在另一个线程里处理,比如invokeLater之类的
    这样就没有理由不能让事件线程休眠了,我不是很确定3楼用的sleep是不是EventDispatchThread(题外话),但这样正好是可以满足你的需求的
      

  5.   


    一样的,修改颜色值,然后触发repaint()事件或者updateUI()事件。其实说到底整个过程分为两步:
    定时线程:生成某个对象,或修改了某个值;然后触发事件;
    GUI线程:执行事件,进行repaint操作,于是新的值或对象的效果从界面上得以体现。
      

  6.   

    这里应该有你要找的答案。看看别人的程序是怎么做到的。
    http://blog.csdn.net/wzj26638719/article/details/7484894Java Swing原创 Spring + Hibernate + mySql实现的纯JAVA版QQ聊天程序,可以说是空前绝后。哈哈。下载地址:http://blog.csdn.net/wzj26638719/article/details/7484894
    或者http://home.126disk.com/microsoftsun管理员增删禁用户,增删改部门。每个用户可创建群、退出群。
    可以私聊,群聊,发表情,发截屏,发闪屏,发在线和离线文件,消息记录永久保存。
    记住登录密码自动登录,切换用户界面皮肤风格(10几种),个性化消息内容和自己名字的颜色字体等。
    最近联系人,消息提示,悬浮图标等等。
    当新消息到达时,悬浮图标会变成一辆汽车在屏幕上跑来跑去,越跑越快,直到一定的速度后再恢复减速。
    直到您收取了新消息为止。
    系统错误日志记录,自动更新。现在可以下载了。运行界面截图请到下载地址去看吧。更多功能,请在安装运行以后,查看帮助菜单。主要使用了java的Socket、多线程、IO、JDBC、Swing。工具netBeans、MySql、Navicat 
     
     
      

  7.   

    问题的关键是在其他线程里更改控件的颜色,符不符合Swing线程安全的要求?
      

  8.   


    客观地说,是存在风险的,常规情况下的问题是脏读。因为实际上即便你不谈论GUI,任何对同一对象的并发操作,都是存在线程不安全风险的,要么就要用synchronized来进行同步保护,要么就选择接受该风险。比如对你要操作的image对象进行保护(两边都要做这个动作):
    synchronized(img) {
    }
    但其实我认为如果处理得好的话,是可以在不使用synchronized的情况下,让风险仅限于脏读的;比如我3楼的例子就是。
    如果你即不想复杂的用synchronized来进行保护,又不想接受该风险。那么就需要直接借用GUI线程了,方法是:
    SwingUtilities.invokeLater(xxoo)
      

  9.   

    我想你还有5楼那位可能对SwingUtilities.invokeLater(xxoo)的理解有点错误。一开始我也考虑用SwingUtilities.invokeLater(xxoo),但是发现SwingUtilities.invokeLater(xxoo)不是创建多个线程然后排队执行,而是把任务加到GUI线程中执行。也就是说如果xxoo有休眠操作的话其实是对GUI线程休眠。不信你们可以测试一下。
      

  10.   

    我没理解错误啊,我说的就是GUI线程,是你理解错误了如果你即不想复杂的用synchronized来进行保护,又不想接受该风险。那么就需要直接借用GUI线程了,方法是:
    SwingUtilities.invokeLater(xxoo)
    方法就是定时调用来借助GUI线程,这有啥问题?public void run() {
      while (true) {
        SwingUtilities.invokeLater(xxoo);
        Thread.sleep(1000); 
      }
    }
      

  11.   

    我开始弄错了,invokeLater是仍旧在Event Dispathcing thread上执行,但效果却是异步的,在其中调用sleep应该就是让Event Dispathcing thread休眠invokeLaterpublic static void invokeLater(Runnable doRun)    Causes doRun.run() to be executed asynchronously on the AWT event dispatching thread. This will happen after all pending AWT events have been processed. This method should be used when an application thread needs to update the GUI.
      

  12.   

    不过挺奇怪的,号称是异步,但也是等待所有待发AWT事件被处理完毕后才会执行。