当前位置: 首页 > 编程笔记 >

Java Swing 多线程加载图片(保证顺序一致)

司空鸿熙
2023-03-14
本文向大家介绍Java Swing 多线程加载图片(保证顺序一致),包括了Java Swing 多线程加载图片(保证顺序一致)的使用技巧和注意事项,需要的朋友参考一下

大二的时候做的课程设计,图片管理器,当时遇到图片很多的文件夹,加载顺序非常慢。虽然尝试用多个Thread加载图片,却无法保证图片按顺序加载。直到今天学会了使用Callable接口和Future接口,于是心血来潮实现了这个功能。

废话不多说,看代码。

多线程加载图片(核心):

package com.lin.imagemgr;

import java.awt.Dimension;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.stream.Collectors;
import javax.swing.ImageIcon;
import javax.swing.JLabel;

import net.coobird.thumbnailator.Thumbnails;

public class ImageMgr {
 private static ImageMgr instance = new ImageMgr();
 private ImageMgr() {}
 public static ImageMgr getInstance() {
  return instance;
 }

 //线程池
 private ExecutorService executor = Executors.newFixedThreadPool(8);

 public List<JLabel> loadImages(String path) {
  List<JLabel> images = new ArrayList<>();
  File file = new File(path);
  if (!file.isDirectory()) {
   throw new RuntimeException("need directory!");
  }
  File[] files = file.listFiles(new FilenameFilter() {

   @Override
   public boolean accept(File dir, String name) {
    //thumbnail只支持jpg??
    if (name.endsWith(".jpg")) {
     return true;
    }
    return false;
   }
  });

  //并发加载图片,并使用Future保存加载结果
  List<Future<MyLabel>> futures = new ArrayList<>();
  for (final File f : files) {
   Future<MyLabel> future = executor.submit(() -> {
    return new MyLabel(f.getName(), f.getAbsolutePath());
   });
   futures.add(future);
  }

  //等待所有并发加载返回结果
  try {
   for (Future<MyLabel> future : futures) {
    MyLabel icon = future.get();
    images.add(icon);
   }
  } catch (InterruptedException e) {
   e.printStackTrace();
  } catch (ExecutionException e) {
   e.printStackTrace();
  }

  //Java8使用stream API 进行排序
  List<JLabel> sortedList = images.stream().sorted().collect(Collectors.toList());

  return sortedList;
 }

 //继承JLabel并实现Comparable接口,从而对JLabel进行排序
 private static class MyLabel extends JLabel implements Comparable<MyLabel>{
  private static final long serialVersionUID = 1L;
  private String fileName;

  public MyLabel(String fileName, String fullPath) {
   this.fileName = fileName;
   //使用thumbnailator生成缩略图
   try {
    BufferedImage bufferedImage = Thumbnails.of(fullPath) 
    .size(100, 120)
    .asBufferedImage();
    setIcon(new ImageIcon(bufferedImage));
    setPreferredSize(new Dimension(100, 120));
   } catch (IOException e) {
    e.printStackTrace();
   }
  }

  @Override
  public int compareTo(MyLabel o) {
   int result = this.fileName.compareTo(o.fileName);
   return result;
  }


 }

}

Swing界面:

package com.lin.imagemgr;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;

public class MainFrame extends JFrame{
 private static final long serialVersionUID = 1L;
 private JTextField pathField;
 private JButton showBtn;
 private JPanel contentPanel;

 public void init() {
  JPanel topPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 5, 0));
  topPanel.setPreferredSize(new Dimension(800, 40));
  pathField = new JTextField(50);
  showBtn = new JButton("显示图片");
  topPanel.add(pathField);
  topPanel.add(showBtn);
  getContentPane().add(BorderLayout.NORTH, topPanel);
  contentPanel = new JPanel();
  contentPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 5, 5));
  contentPanel.setPreferredSize(new Dimension(750, 1800));
  JScrollPane jsp = new JScrollPane(contentPanel);
  getContentPane().add(BorderLayout.CENTER, jsp);

  showBtn.addActionListener((e) -> {
   try {
    loadImages();
   } catch (Exception ex) {
    ex.printStackTrace();
   }
  });

  setSize(800, 650);
  setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  setLocationRelativeTo(null);
  setVisible(true);
 }

 public void loadImages() {
  contentPanel.removeAll();
  String path = pathField.getText();
  long start = System.currentTimeMillis();
  List<JLabel> images = ImageMgr.getInstance().loadImages(path);
  for (JLabel label :images) {
   contentPanel.add(label);
  }
  contentPanel.updateUI();
  long end = System.currentTimeMillis();
  System.out.println("加载需要" + (end - start) + "毫秒!");

 }

 public static void main(String[] args) {
  new MainFrame().init();
 }

}

运行结果

在我的电脑上,加载92张图片并渲染到界面上,总共花了1568毫秒。大家可以找一个图片很多的文件夹,尝试加载大量图片的情况。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持小牛知识库。

 类似资料:
  • 本文向大家介绍javascript顺序加载图片的方法,包括了javascript顺序加载图片的方法的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了javascript顺序加载图片的方法。分享给大家供大家参考。具体如下: javascript监听一个图片是否加载完毕 如果加载完成再加载下一张,不是一次性从服务器加载 减少服务器压力, 可用到的地方:比如制作类似google地图的应用,可以使小

  • 我们有1000多条数据,请求1000次第三方个接口, 效率很是低下! 所以我想利用多线程的方式快速的调用完这1000次接口请求并处理响应 但是有个问题,线程是在for循环中执行的,调用顺序肯定是错乱的,这就导致接调用后 返回的结果肯定和List中的不匹配了··· 这种情况怎么能保证顺序呢?这是我的代码

  • 在我的应用程序中,在程序的整个生命周期中,有n个操作必须依次发生。我决定为每个操作创建一个线程,让它们执行一次run方法,然后等待所有其他线程都执行相同的操作,等待轮到它,然后再次执行,依此类推,而不是创建实现这些操作的方法并在while(true)循环中按顺序调用它们。。。 为了实现这个机制,我创建了一个名为StatusHolder的类,它有一个名为threadTurn的字段(表示应该执行哪个线

  • 问题内容: 我知道保护图像下载的最佳方法不是一开始就将其放在互联网上。 我假设没有100%防止图片下载,并且如果用户可以在Internet上看到图片,那么他只要有一点经验就可以找到下载图片的权限。 我知道透明或覆盖图像,或者使用CSS属性来保护它并防止右键单击下载,但是在那里 其他使图片下载复杂化并因此阻止大多数用户下载图片的方式? 这是简单的代码开头: 问题答案: 根本没有办法阻止用户执行特定任

  • RabbitMQ保证在相同的发布通道- 1.)我有一个单一的线程发布消息在一个单一的交换2.(我有其他线程的集合发布消息在不同的交流有时创造新的消费者为不同的交流 使用缓存连接工厂,它具有通道缓存。每次发布时,它都会进入缓存以获取通道。因为其他线程正在发布和使用,所以不能保证同一通道将被我的主线程用于后续发布。即使我有一个缓存,这也是真的。有人回避过这个问题吗? 理想情况下,我希望为publish