如何在Java的ImageLoader中实现ImageIcon同步获取
问题原因
调用loader.start()后线程仅进入就绪状态,不会立刻执行run方法加载图片,此时立即调用returnIcon()获取的icon自然为null。仅给returnIcon()加synchronized只能保证读操作的原子性,无法实现「等待加载完成再返回」的逻辑,同时需注意Swing的UI渲染线程(EDT)不能被阻塞,否则会导致界面无响应。
方案1:基础同步等待(仅适合非UI线程调用场景)
采用wait/notify机制实现加载完成的等待逻辑,修改ImageLoader类如下:
package util; import javax.swing.ImageIcon; public class ImageLoader extends Thread { private String file; private ImageIcon icon; public ImageLoader(String file) { this.file = file; } @Override public void run() { ImageIcon icon = new ImageIcon(this.file); synchronized (this) { this.icon = icon; // 加载完成后唤醒所有等待的线程 notifyAll(); } // Thread类的run方法默认是空实现,无需调用super.run() } public synchronized ImageIcon returnIcon() throws InterruptedException { // 循环判断防止虚假唤醒 while (icon == null) { wait(); } return this.icon; } }
注意:该方案如果直接在GUI初始化代码中调用会卡住UI线程,不适合Swing场景,仅适合后端非UI线程的同步获取场景。
方案2:Swing场景最优方案(异步回调更新UI)
Swing要求所有UI组件的更新必须在EDT线程执行,且不能阻塞EDT,因此推荐用异步回调的方式,加载完成后主动更新JLabel,无需主动等待返回:
- 定义加载回调接口
public interface ImageLoadCallback { void onLoadSuccess(ImageIcon icon); }
- 修改
ImageLoader支持回调
package util; import javax.swing.ImageIcon; import javax.swing.SwingUtilities; public class ImageLoader extends Thread { private String file; private ImageLoadCallback callback; public ImageLoader(String file, ImageLoadCallback callback) { this.file = file; this.callback = callback; } @Override public void run() { ImageIcon icon = new ImageIcon(this.file); // 切回EDT线程执行回调更新UI SwingUtilities.invokeLater(() -> callback.onLoadSuccess(icon)); } }
- 修改GUI调用逻辑
private void initUI() { int bilderAnzahl = 3; this.setLayout(new GridLayout(1, 1)); JPanel bilderPanel = new JPanel(new GridLayout(bilderAnzahl, 1)); for (int i = 0; i < bilderAnzahl; i++) { JLabel jbl = new JLabel(); // 传入回调,加载完成后自动设置icon ImageLoader loader = new ImageLoader("./Picture.jpg", jbl::setIcon); loader.start(); jbl.setBorder(BorderFactory.createEtchedBorder()); jbl.setPreferredSize(new Dimension(200, 50)); bilderPanel.add(jbl); } JScrollPane scrPn = new JScrollPane(bilderPanel); this.add(scrPn); }
该方案既不会阻塞UI线程,也能保证图片加载完成后立刻更新到界面上,是Swing异步加载资源的标准实现方式。
内容的提问来源于stack exchange,提问作者Richi 15000
相关产品推荐
相关产品推荐

