gpt4 book ai didi

java - java.awt.GraphicsConfiguration 是线程安全的吗?有哪些替代方案

转载 作者:太空宇宙 更新时间:2023-11-04 13:52:37 25 4
gpt4 key购买 nike

我正在扩展 javax.swing.JComponent 以显示可变数量的图 block ,这些图 block 都具有相同的大小。

如果图 block 需要新的外观,SwingWorkerdoInBackground() 会为其渲染一个新的 BufferedImage。在 done() 中,存储图像并调用 JComponent.repaint(),指示更新的区域和预期的延迟。被重写的 JComponent.paintComponent() 将知道要做什么。

图 block 的大小可以通过 GUI 更改。显然,当 SwingWorkerStateValuePENDINGSTARTED 时,可能会发生这样的请求。

我认为支持 cancel() 没有多大意义;它使代码变得复杂,并且由于实际渲染不会花费很长时间,因此其效果将是最小的(如果工作人员必须等待比执行所需的时间更长的时间,甚至是有害的)。相反,我想提高效率,并且如果同一图 block 存在 PENDING 代码,则 EDT 代码不会启动新的 SwingWorker 代码。然后,SwingWorker 只需要在 doInBackground() 启动时获取最新设置,并检查是否应该将其结果存储在 done() 中。

那么 SwingWorker 使用的 BufferedImage 应该在哪里生成呢?这些似乎是选项:

  • 预先创建它。缺点:必须选择最大尺寸,因为具体尺寸未知,并且由于 paintComponent() 可能同时运行,因此必须始终为所有图 block 保留最大尺寸的两个图像(想想 ViewPort;动态解决方案暂时只需要可见图 block 实际所需尺寸的第二个图像)。
  • 在创建 SwingWorker 时创建它。缺点:必须提供最大大小,因为一旦 doInBackground() 被触发,就无法知道需要哪个大小。
  • SwingWOrker 中创建它。问题:鉴于 JComponent.paintComponent() 可能需要经常调用 drawImage(),建议使用 GraphicsConfiguration.createCompatibleImage() 创建此图像。这可能会打破 AWT 的单线程限制。

我更喜欢以下内容,但由于 GraphicsConfiguration 属于 AWT,并且实现取决于平台,这样做安全吗?

  ...
final GraphicsConfiguration gc = this.getGraphicsConfiguration();
if ((obj.worker == null) ||
(obj.worker.getState() != SwingWorker.StateValue.PENDING)) {
obj.worker = new SwingWorker<BufferedImage, Void>() {
@Override public BufferedImage doInBackground() {
... // acquire size info via synchronised access
final BufferedImage img = gc.createCompatibleImage(...);
...
return img;
}
@Override public void done() {
if (obj.worker == this) {
obj.worker = null;
try { obj.image = this.get(); }
catch (Throwable t) { ... System.exit(1); }
Outer.this.requestTileRepaint(...);
}
}
};
obj.worker.execute();
}
...

澄清

查看上面的代码,有人可能会认为此解决方案不存在真正的多线程问题,因为 GraphicsConfiguration 对象是在 EDT 上专门为该特定工作线程创建的。然而,

  • 我正在查看抽象类实现,它包含静态对象
  • 每次调用 Component.getGraphicsConfiguration() 可能会返回相同的对象引用。

我认为最安全的方法是从 EDT 上的 GraphicsConfiguration 中提取所有相关信息,将其传递给工作人员,并在那里获取具有合适配置的 new BufferedImage() 。但我在网上发现了一些提示,结果可能会导致 drawImage() 性能出现令人惊讶的影响,这表明可能存在未明确涵盖的配置方面。

最佳答案

采用 haraldK 的想法,这是一个线程安全的解决方案,我已经在装有 Java SE 1.6.0_26 的 Linux PC 和装有 Java SE 1.8.0_40 的 Windows 8.1 笔记本上进行了测试。 (显然,代码可以改进,但这超出了本问答的范围。)

在这两个平台上,根据处理器速度进行调整后的性能相当,而且在这两个平台上,Transparency.BITMASK 是通过 BufferedImage.TYPE_CUSTOM 处理的,而 Transparency.OPAQUETransparency.TRANSLUCENT 使用特定的对应 BufferedImage.TYPE_* 值。

此外,在这两个平台上,使用两个 new BufferedImage() 调用之间没有明显的性能差异,而 GraphicsConfiguration.createCompatibleImage() 速度肯定慢了(30% 到 50%)。

整个机制由内部类提供。外部类extends javax.swing.JComponent 因此在该级别根本没有同步。但是,SwingWorker 是匿名内部类,并部署图像创建同步机制。

在测试的平台上,BufferedImage.getType()的两个类别之间的区别似乎是不必要的,但谁知道呢。

就我而言,内部类还包含 SwingWorker 需要的其他信息。

private static final class WokerSync
{
private Object refImageMutex = new Object();
private BufferedImage refImageOpaque = null;
private BufferedImage refImageTranspMask = null;
private BufferedImage refImageTranslucent = null;

public void setRefImagesFromEDT(final GraphicsConfiguration grConf) {
if (grConf != null) {
synchronized(this.refImageMutex) {
this.refImageOpaque = grConf.createCompatibleImage(1, 1, Transparency.OPAQUE);
this.refImageTranspMask = grConf.createCompatibleImage(1, 1, Transparency.BITMASK);
this.refImageTranslucent = grConf.createCompatibleImage(1, 1, Transparency.TRANSLUCENT);
}
}
}
private BufferedImage getCompatibleImage(final BufferedImage refImage, final int width, final int height) {
BufferedImage img = null;
if (refImage != null) {
final int grType = refImage.getType();
if (grType == BufferedImage.TYPE_CUSTOM) {
final ColorModel cm = refImage.getColorModel();
final WritableRaster wr = cm.createCompatibleWritableRaster(width, height);
final String[] ps = refImage.getPropertyNames();
final int pl = (ps == null) ? 0 : ps.length;
final Hashtable<String,Object> ph = new Hashtable<String,Object>(pl);
for (int pi=0; pi<pl; pi++) {
ph.put(ps[pi], refImage.getProperty(ps[pi]));
}
img = new BufferedImage(cm, wr, cm.isAlphaPremultiplied(), ph);
} else {
img = new BufferedImage(width, height, grType);
}
}
return img;
}
public BufferedImage getCompatibleImageOpaque(final int width, final int height) {
BufferedImage img = null;
synchronized(this.refImageMutex) {
img = this.getCompatibleImage(this.refImageOpaque, width, height);
}
return img;
}
public BufferedImage getCompatibleImageTranspMask(final int width, final int height) {
BufferedImage img = null;
synchronized(this.refImageMutex) {
img = this.getCompatibleImage(this.refImageTranspMask, width, height);
}
return img;
}
public BufferedImage getCompatibleImageTranslucent(final int width, final int height) {
BufferedImage img = null;
synchronized(this.refImageMutex) {
img = this.getCompatibleImage(this.refImageTranslucent, width, height);
}
return img;
}
}

关于java - java.awt.GraphicsConfiguration 是线程安全的吗?有哪些替代方案,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30148795/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com