经过许多小时的调试和分析后,我终于设法找出竞争条件的原因。解决它是另一回事!Java AWT drawImage竞态条件 - 如何使用同步来避免它
为了看到实际的竞争状况,我在调试过程中录制了一段视频。我从那时起就进一步了解了这种情况,所以请原谅贫穷的评论和作为调试过程一部分而实施的愚蠢机制。
http://screencast.com/t/aTAk1NOVanjR
所以,这种情况:我们有一个双缓冲实现的表面(即java.awt.Frame中或窗口),其中有一个正在执行的线程,基本上连续循环,调用渲染进程(执行用户界面布局并将其渲染到后台缓冲区),然后进行后期渲染,将渲染区域从后台缓冲区传送到屏幕。
这里是双重的伪代码版本(完整版线Surface.java 824)缓冲呈现:
public RenderedRegions render() {
// pseudo code
RenderedRegions r = super.render();
if (r==null) // nothing rendered
return
for (region in r)
establish max bounds
blit(max bounds)
return r;
}
与任何AWT表面实现,它还实现(线507 AWT.java - 链接限制:( - 使用Surface.java链接,与高原/ AWT.java更换核心/ Surface.java)油漆/更新覆盖这也从位块传输的后备缓冲到屏幕上:
public void paint(Graphics gr) {
Rectangle r = gr.getClipBounds();
refreshFromBackbuffer(r.x - leftInset, r.y - topInset, r.width, r.height);
}
阻击器实现(使用的drawImage线371 AWT.java)()函数:
/** synchronized as otherwise it is possible to blit before images have been rendered to the backbuffer */
public synchronized void blit(PixelBuffer s, int sx, int sy, int dx, int dy, int dx2, int dy2) {
discoverInsets();
try {
window.getGraphics().drawImage(((AWTPixelBuffer)s).i,
dx + leftInset, dy + topInset, // destination topleft corner
dx2 + leftInset, dy2 + topInset, // destination bottomright corner
sx, sy, // source topleft corner
sx + (dx2 - dx), sy + (dy2 - dy), // source bottomright corner
null);
} catch (NullPointerException npe) { /* FIXME: handle this gracefully */ }
}
(警告:这是我开始变得清晰假设)
这里的问题似乎是个drawImage是异步的一个!从refreshBackBuffer()通过绘制/更新blit首先被调用,但出现秒。
所以... blit已经同步。防止竞争状况的显而易见的方式不起作用。 :(
到目前为止,我已经提出了两个解决方案,但他们都不是理想的:在接下来的
重块传送渲染过程
缺点:性能损失,仍然得到了一点闪烁由于遇到竞争状态(有效屏幕 - >无效屏幕 - >有效屏幕)时不要的blit油漆/更新,而不是设置刷新范围,并使用这些边界下一个渲染通道
缺点:让黑当屏幕无效时闪烁主要应用程序线程正在追赶
这里(1)似乎是两个邪恶中较小的一个。 编辑:和(2)不起作用,获得空白屏幕......(1)工作正常,但只是掩盖了问题,可能仍然存在。
由于我对同步以及如何使用它的理解不够,我似乎无法想象它是一种锁定机制,它以某种方式说明了drawImage()的异步特性。
或者也许使用ImageObserver?
注意的是,由于应用程序的性质(Vexi,对于那些有兴趣,网站是过时的,我只能用2个超链接)渲染线程必须是油漆/更新之外 - 它有一个单线程脚本模型和布局过程(渲染的子流程)调用脚本。
我假设你的意思是'发生了什么 - 问题仍然存在。我只是尝试将blit代码复制到paint方法中,并且其行为相同。 (FWIW它并没有真正的区别,因为paint已经通过refreshFromBackBuffer间接地调用了blit,但为了彻底,我尝试了你的建议。) – 2011-02-10 01:50:24