You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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,无需主动等待返回:

  1. 定义加载回调接口
public interface ImageLoadCallback {
    void onLoadSuccess(ImageIcon icon);
}
  1. 修改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));
    }
}
  1. 修改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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 19:45:01