原文地址:http://twaver.servasoft.com/?p=658

第一和第二篇后,GUI线程安全的原理性内容基本就这些了,如果你是搞学术理论研究的基本就不用继续阅读下面几篇我要继续八卦的内容,下面的内容都是针对具体技术平台的细节问题了。

static void Main(string[] args)
{TextBlock text = new TextBlock();
}
private InputManager()
{// STA Requirement//// Avalon doesn't necessarily require STA, but many components do.  Examples// include Cicero, OLE, COM, etc.  So we throw an exception here if the// thread is not STA.if(Thread.CurrentThread.GetApartmentState() != ApartmentState.STA){throw new InvalidOperationException(SR.Get(SRID.RequiresSTA));}

看看System.Windows.Input.InputManager的代码实现你就明白了,原来TextBlock的创建要求在STA环境中,你要问我啥叫STA,我喜欢将其简单理解为这玩意儿就是我们前面提到的EDT,也就是那个全局唯一的UI Thread,具体的解释你可以看Component_Object_Model#Threading_in_COM的解释,当年读潘爱民翻译的《COM本质论》差点让我没了继续当程序员的勇气,以下引用了一段话你就看着玩就行

There are three types of Apartment Models in the COM world: Single-Threaded Apartment (STA), Multi-Threaded Apartment (MTA), and Neutral Apartment. Each apartment represents one mechanism whereby an object’s internal state may be synchronized across multiple threads.
The Single-Threaded Apartment (STA) model is a very commonly used model. Here, a COM object stands in a position similar to a desktop application’s user interface. In an STA model, a single thread is dedicated to drive an object’s methods, i.e. a single thread is always used to execute the methods of the object. In such an arrangement, method calls from threads outside of the apartment are marshalled and automatically queued by the system (via a standard Windows message queue). Thus, there is no worry about race conditions or lack of synchronicity because each method call of an object is always executed to completion before another is invoked.

上面的一行代码其实已经说明了问题Thread.CurrentThread.GetApartmentState() != ApartmentState.STA,也就是main启动运行的线程并不是EDT,回想一下WindowsForms和WPF的应用程序的main是怎么写的,是的就是这个[STAThread]起的作用,把上面代码加上这个[STAThread]你就不会再怀疑自己智商了。

[STAThread]
static void Main()
{... ...
}

《Applications = Code + Markup》这本是我学习WPF的第一本书,讲解思路非常符合传统程序员口味,上半本先完全用OO的方式解释了WPF组件的来龙去脉,下半本才开始设计XAML的标签应用,说实话我很看不惯现在的快餐式书籍,一上来就是XAML用户连WPF组件Dependency Properties这种最重要的新机制都完全不明白的情况下就开始写项目,同样的还有一上来就开始鼓吹如何用MXML快速创建Flex程序,本末倒置不介绍背后ActionScript语言实现原理的书籍,更有一大堆历史杯具人物写了多年JSP不知道啥是Java的OO。

前几天逛书店发现蔡学庸也翻译了《Applications = Code + Markup》一书,刚毕业时买过他的一本经典《Java夜未眠》,那时候作为个junior程序员的我手头也几个钱,晚上也没法去新天地泡mm的方式夜未眠,只好翻翻学庸兄的《Java夜未眠》,不过这些年薪水提高了反而不去书店买书了,原因很简单译书上得不到最新的技术资料而且翻译往往后失去作者的原味,相信《红楼梦》的译书很难接近原著的味道,扯远了,我不是要推销《Applications = Code + Markup》,更不是要打击蔡学庸译书的销量(我还是很尊重且喜欢订阅学庸兄的blog,如果学庸看到小弟此文希望能有机会交个朋友),只是想引用书中一段话帮助大家理解:

In any WPF program, the [STAThread] attribute must precede Main or the C# compiler will complain. This attribute directs the threading model of the initial application thread to be a single-threaded apartment, which is required for interoperability with the Component Object Model (COM). “Single-threaded apartment” is an old COM-era, pre-.NET programming term, but for our purposes you could imagine it to mean our application won’t be using multiple threads originating from the runtime environment.

使用TWaver Java的客户应该有印象,TWaver Java Demo的启动代码和地球上99%的Swing的main代码不一样,套了个SwingUtilities.invokeLater,曾经有个客户程序启动再大部分机器上都正常,结果在一台双核(N年前双核可是很洋相配置)的机器启动总出错,去现场帮忙找原因时我查的第一行代码就是main的启动代码,发现用户直接就在main里面创建各种UI组件,同时还起了Thread做各种业务,我就让他改成和TWaver Demo一样,启动时套了个SwingUtilities.invokeLater,你猜怎么样我竟然“被”允许回家了,这是我在赛瓦这些年最短的现场支持经历,像我这种不敢坐飞机的(去年做了38个小时火车去了哈尔滨培训客户)做了十几个小时的火车竟然现场待了几分钟就回家了,实在是亏啊。

public static void main(String[] args) {SwingUtilities.invokeLater(new Runnable(){public void run() {Demo.init();DemoFrame demoFrame = new DemoFrame();demoFrame.setVisible(true);}});
}

很简单,因为main启动的函数并不是Swing的事件派发线程,SwingUtilities.isEventDispatchThread()你可以调用该函数测试一下,而地球99%的代码直接非EDT里面做UI的工作时极其危险的,大部分程序都是初始化界面然后show就结束了,这样基本能侥幸不出错,但如果你调用了show之后再有代码在执行,而且是操作到UI组件的地方拿基本必然会导致问题,但为了您的生命安全还请遵守GUI线程安全规则。这里有更多的解释可以参考:

public class MyApplication {
public static void main(String[] args) {
JFrame f = new JFrame(“Labels”);
// Add components to
// the frame here…
f.pack();
f.show();
// Don’t do any more GUI work here…
}
}
All the code shown above runs on the “main” thread. The f.pack() call realizes the components under the JFrame. This means that, technically, the f.show() call is unsafe and should be executed in the event-dispatching thread. However, as long as the program doesn’t already have a visible GUI, it’s exceedingly unlikely that the JFrame or its contents will receive a paint() call before f.show() returns. Because there’s no GUI code after the f.show() call, all GUI work moves from the main thread to the event-dispatching thread, and the preceding code is, in practice, thread-safe.

另外我挺喜欢现在.NET的线程安全问题上再底层框架做的检查工作,就像刚才Console操作TextBlock的代码,很容易程序员就能知道问题所在,而Swing这点上是最让我不满意的地方,你不提示检查我这些在普通线程操作UI组件就算了,某些情况下Swing还自作聪明的在内部帮你SwingUtilities.invoke***,结果常常导致很多客户质问我为什么我在普通线程调用revalidate()不出错,你们还非得让我以这么丑陋的代码方式到处去SwingUtilities.invoke,我觉得Swing这样的实现会误导程序员放松对线程安全的戒备,Swing仅仅在很少很少很少的函数上做了判断内部处理,如果大家觉得JComponent.revalidate()可以随意调用,那岂不TableModel、TreeModel…包括TWaver的DataBox和Element都可以不管EDT随意调用了,所以这点上.NET严谨的判断还是能让程序员尽早的规避了很多线程安全问题

public void revalidate() {if (getParent() == null) {// Note: We don't bother invalidating here as once added// to a valid parent invalidate will be invoked (addImpl// invokes addNotify which will invoke invalidate on the// new Component). Also, if we do add a check to isValid// here it can potentially be called before the constructor// which was causing some people grief.return;}if (SwingUtilities.isEventDispatchThread()) {invalidate();RepaintManager.currentManager(this).addInvalidComponent(this);}else {Runnable callRevalidate = new Runnable() {public void run() {revalidate();}};SwingUtilities.invokeLater(callRevalidate);}
}

今天要讲的就这些内容,不知道昨天提到TWaver的FileTreeDemo里面还有个多线程的细节,你有没有注意到tree在加载文件是还能看到gif的loading图标,你只要打开tree.setEnableAnimation(true)开关,随时随意间任何element.setIcon(“/demo/tree/file/loading.gif”)设置上任何gif图标,twaver将透明自动的识别gif动画图标,并且让tree上的icon动画起来。这还没啥,有一回我看到用户启动画面竟然有很酷动画的splash screen,我问用户是不是嵌入了Flash,用户说:“用的就是你们的Network做启动界面,只不过放了一个GIF的大Node做主启动界面而已,赛瓦真该开除了你这个傻B,还号称TWaver Evangelist,丢人也不能丢这么大啊”

深入浅出GUI线程安全(三)相关推荐

  1. Android---手动创建线程与GUI线程同步(三)

    Android---手动创建线程与GUI线程同步的第三种方法: 在GUI线程中调用runOnUiThread(Runnable runnable), 此时work Thread与GUI线程在同一个线程 ...

  2. GUI线程安全详解(三)

    2019独角兽企业重金招聘Python工程师标准>>> 继第一和第二篇后,GUI线程安全的原理性内容基本就这些了,如果你是搞学术理论研究的基本就不用继续阅读下面几篇我要继续八卦的内容 ...

  3. python编程(GUI线程和工作线程的同步)

    [ 声明:版权所有,欢迎转载,请勿用于商业用途. 联系信箱:feixiaoxing @163.com] 一般来说,编写gui客户端之外,都要编写几个work thread.因为如果只有一个gui th ...

  4. 多线程之旅七——GUI线程模型,消息的投递(post)与处理

    基于消息的GUI构架 在过去的日子中,大部分编程语言平台的GUI构架几乎没有发生变化.虽然在细节上存在一些差异,比如在功能和编程风格上,但大部分都是采用了相同的构架来响应用户输入以及重新绘制屏幕.这种 ...

  5. Java线程池状态判断源码_深入浅出Java线程池:源码篇

    前言 在上一篇文章深入浅出Java线程池:理论篇中,已经介绍了什么是线程池以及基本的使用.(本来写作的思路是使用篇,但经网友建议后,感觉改为理论篇会更加合适).本文则深入线程池的源码,主要是介绍Thr ...

  6. QT 多线程的实现方法以及GUI线程与其他线程间的通信

    GUI线程 Qt应用程序exec后就会生成一个线程,这个线程就是主线程,在GUI程序中也称为GUI线程.主线程也是唯一允许创建QApplication或QCoreAppliation对象,比并且可以对 ...

  7. 消息机制(GUI线程讲解)

    文章目录 前奏 窗口代码 你能回答这些问题吗? 消息队列: 消息队列在何处呢? 那么Windows如何解决的呢? 重点: 总结: 前奏 首先我们来画一个窗口: 窗口代码 #include<Win ...

  8. java 创建线程_【80期】说出Java创建线程的三种方式及对比

    点击上方"Java面试题精选",关注公众号 面试刷图,查缺补漏 >>号外:往期面试题,10篇为一个单位归置到本公众号菜单栏->面试题,有需要的欢迎翻阅. 一.Ja ...

  9. Android---手动创建线程与GUI线程同步(二)

    本文在上一节Android---手动创建线程与GUI线程同步(一)的基础上来进行改进 上一节我们实现了在子线程中进行耗时工作,并通过Handler更改GUI中的UI,但是我们并不能通过它来获取后台工作 ...

最新文章

  1. DotNetNuke与MemberShip的结合(五年版)第三步修改HttpModule.DNNMembership
  2. Java虚拟机详解02----JVM内存结构
  3. 挺过最艰难的2018,我终将长大
  4. 拓扑检查中的一些问题(为啥没自相交)
  5. 武汉月薪1万5,感到焦虑怎么办?
  6. 常用中国姓氏日文平假名对照表
  7. sap批量创建盘点凭证以及盘点凭证过账
  8. 管道—过滤器简介 软件体系结构
  9. FZU 2213 Common Tangents(公切线)
  10. 程序员的自我进化:技术的广度与深度怎么权衡
  11. linux运行jar的几种方式
  12. 循环彩灯定时器C语言,PLC基本指令及应用,学会控制彩灯,并循环往复工作
  13. 如何用命令ping计算机型号,怎么修改cmd中ping命令的数据包大小?
  14. Pytorch(pip安装示例)
  15. 设置elementui表格的上下左右滚动条
  16. NOKIA 5110屏幕驱动
  17. 诉不尽女儿心事——走进古代女性的闺房(组图)
  18. JCreator 连接数据库
  19. 容器安全检查工具 - Clair v2.0.0
  20. 直播系统源码开发:关于安卓开发工具和obs直播推流

热门文章

  1. c语言ox是什么意思啊,ox什么意思
  2. Top01-0010、img标签的属性
  3. 如何保存微信视频到本地,微信朋友圈怎么发本地的视频。
  4. 利用老路由器来简单监控3D打印机
  5. python编程手机游戏_有哪些python写的游戏
  6. Android与uni-app 互相通信案例(包含源代码)
  7. Home Assistant 开发指南
  8. 如何将tomcat注册成windows系统服务方法
  9. 向上沟通-管理你的上司
  10. ShowMeAI —— Show u 三连