通用线程规则

2017-01-08  本文已影响128人  pr488

原文链接:
http://www.jetbrains.org/intellij/sdk/docs/basics/architectural_overview/general_threading_rules.html

插件应该使用ApplicationManager.getApplication().invokeLater()而不是标准的SwingUtilities.invokeLater()传递控制从后台线程到事件分发线程。这个API允许调用指定modality state,即允许调用执行的模态对话框的堆栈。 传递ModalityState.NON_MODAL意味着在所有模态对话框关闭后执行操作。 传递ModalityState.stateForComponent()意味着可以在指定的组件(对话框的一部分)仍然可见时执行操作。

读/写锁

通常情况下,*IntelliJ平台 *中代码相关的数据结构由一个单独的读写锁监控。这适用于PSI,VFS和项目根模型。

可以从任何线程读取数据,从UI线程读取数据不需要任何特殊的工作。但是,从任何其它线程的读操作都需要使用ApplicationManager.getApplication().runReadAction()包裹,或者简短一点使用ReadAction.run/compute

只允许从UI线程写数据,写操作必须被ApplicationManager.getApplication().runWriteAction()包裹,或者简短一点使用WriteAction.run/compute

除此之外,修改模型只允许从写安全上下文中进行,包括用户操作,安全上下文中的invokeLater调用(查阅下一部分)和事务(TransactionGuard.submitTransaction)。你可能无法从UI渲染器或SwingUtilities.invokeLater调用中修改PSI、VFS或项目模型。更多详情请查阅TransactionGuard文档。

你不能在读写操作之外访问模型。相关对象不能保证在几个连续的读取操作之间存在。 所以根据经验,每当你开始一个读取操作前都应确认说操作的PSI / VFS /项目/模块是否仍然有效。

invokeLater

插件应该使用ApplicationManager.getApplication().invokeLater()而不是标准的SwingUtilities.invokeLater()传递控制从后台线程到事件分发线程。这个API允许调用指定模态状态,即允许调用执行的模态对话框的堆栈。

如果你的UI线程活动需要访问基于文件的索引(如正在进行项目范围的PSI分析,解析引用等等),请使用DumbService#smartInvokeLater。这样,你的活动将在所有可能的索引进程完成后运行。

防止UI冻结

后台线程不应执行长时间的读取操作。原因是如果UI线程需要写操作(如用户输入某些东西),它必须尽快获取控制权,否则在所有后台线程都释放读操作之前UI将被冻结。

最著名的方法是每当即将发生写操作时取消后台读取操作,稍后重新启动后台读取操作。 编辑器高亮显示,代码补全,转到类/文件等操作都是这样的。 有两种推荐的方法:

在这两种方法中,每个读取操作的开始你应该总是检查所用对象是否仍然有效,整个操作是否仍然有意义(即未被用户取消,项目未被关闭等)。

如果你正在进行的活动必须访问基于文件的索引(如正在进行项目范围的PSI分析,解析引用等等),你应该重写ReadTask#runBackgroundProcess并使用"smart-mode"读取操作:DumbService.getInstance(project).runReadActionInSmartMode(() -> performInReadAction(indicator))

上一篇下一篇

猜你喜欢

热点阅读