为了账号安全,请及时绑定邮箱和手机立即绑定

多线程(即基于线程池)Java 应用程序中的损坏结果

多线程(即基于线程池)Java 应用程序中的损坏结果

绝地无双 2023-09-27 16:24:21
我正在尝试 Java 中的多线程,更具体地说,是线程池。作为测试,我编写了一个应用程序,该应用程序仅使用多线程来更改图像的颜色以提高速度。然而,由于某种我不知道的原因,根据我如何设置此测试,我得到的结果已损坏。下面我将描述测试应用程序如何与完整的源代码一起工作。非常欢迎任何帮助!谢谢你!测试应用我有一个 400x300 像素的图像缓冲区,用深蓝色初始化,如下所示:程序必须用红色完全填充它。尽管我可以简单地循环所有像素,并按顺序将每个像素着色为红色,但为了提高性能,我决定利用并行性。因此,我决定用单独的线程填充每个图像行。由于行数(300 行)比可用 CPU 核心数大得多,因此我创建了一个线程池(包含 4 个线程),它将消耗 300 个任务(每个任务负责填充一行)。该计划的组织如下:RGB 类:将像素颜色保存在双精度数 3 元组中。RenderTask 类:用红色填充图像缓冲区的给定行。渲染器类:创建图像缓冲区。使用“newFixedThreadPool”创建线程池。创建 300 个任务供线程池使用。完成线程池服务。将图像缓冲区写入 PPM 文件。一切似乎都适用于该代码,并且我得到了预期的红色图像缓冲区,如下所示:问题但是,如果我修改 RenderTask.run() 方法,使其按顺序多次重复设置同一缓冲区位置的颜色,如下所示(我将其称为Version 2):    @Override    public void run() {           for(int column = 0; column < row_width; ++column) {            for(int s = 0; s < 256; ++s) {                image_buffer[current_row][column] =  new RGB(1.0, 0.0, 0.0);            }        }    }然后我得到以下损坏的图像缓冲区:实际上,每次运行程序的结果都不同,但总是损坏。据我了解,没有两个线程同时写入同一内存位置,因此似乎没有出现竞争情况。即使在我认为不会发生的“错误共享”的情况下,我也期望只会降低性能,而不是损坏结果。因此,即使有冗余的分配,我也希望得到正确的结果(即完全红色的图像缓冲区)。所以,我的问题是:如果程序的版本 2 与版本 1 的唯一区别是赋值操作在线程范围内冗余执行,为什么会发生这种情况?是否会出现某些线程在完成之前就被销毁的情况?这会是 JVM 中的错误吗?或者我错过了一些微不足道的事情?(最有力的假设:)感谢你们!!
查看完整描述

2 回答

?
撒科打诨

TA贡献1934条经验 获得超2个赞

ExecutorService.shutdown() 不会等待其所拥有的任务终止,它只会停止接受新任务。

调用 shutdown 后,如果您想等待执行程序服务完成,则应该在执行程序服务上调用 waitTermination。

因此,当您开始将图像写入文件时,所有任务尚未完成执行。


查看完整回答
反对 回复 2023-09-27
?
宝慕林4294392

TA贡献2021条经验 获得超8个赞

要添加答案,您可以使用以下代码来关闭线程池


以下方法分两个阶段关闭 ExecutorService,首先调用 shutdown 拒绝传入任务,然后调用 shutdownNow(如有必要)取消任何延迟任务:


void shutdownAndAwaitTermination(ExecutorService pool) {

  pool.shutdown(); // Disable new tasks from being submitted

  try {

    // Wait a while for existing tasks to terminate

    if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {

      pool.shutdownNow(); // Cancel currently executing tasks

      // Wait a while for tasks to respond to being cancelled

      if (!pool.awaitTermination(60, TimeUnit.SECONDS))

          System.err.println("Pool did not terminate");

    }

  } catch (InterruptedException ie) {

    // (Re-)Cancel if current thread also interrupted

    pool.shutdownNow();

    // Preserve interrupt status

    Thread.currentThread().interrupt();

  }

}


查看完整回答
反对 回复 2023-09-27
  • 2 回答
  • 0 关注
  • 79 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信