From 8091bbb23db49779a13950b6f4ad173ab084f332 Mon Sep 17 00:00:00 2001 From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> Date: Thu, 15 Oct 2026 23:21:34 -0700 Subject: [PATCH] Stop locking every RegionImage pixel write Scan workers write distinct pixels of a region image, and saves only start after every scan for the region has finished, so the lock in setPixel was only needed to allocate the pixel array. Allocate it with double-checked locking on a volatile field instead, and leave pixel writes unsynchronized. --- .../common/render/output/RegionImage.java | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/common/src/main/java/xyz/jpenilla/squaremap/common/render/output/RegionImage.java b/common/src/main/java/xyz/jpenilla/squaremap/common/render/output/RegionImage.java index 60c513dc..ca609aeb 100644 --- a/common/src/main/java/xyz/jpenilla/squaremap/common/render/output/RegionImage.java +++ b/common/src/main/java/xyz/jpenilla/squaremap/common/render/output/RegionImage.java @@ -32,7 +32,7 @@ public final class RegionImage { private final RegionCoordinate region; private final Path directory; private final int maxZoom; - private int @Nullable [][] pixels = null; + private volatile int @Nullable [][] pixels = null; public RegionImage(final RegionCoordinate region, final Path directory, final int maxZoom) { this.region = region; @@ -40,14 +40,25 @@ public RegionImage(final RegionCoordinate region, final Path directory, final in this.maxZoom = maxZoom; } - public synchronized void setPixel(final int x, final int z, final int color) { - if (this.pixels == null) { - this.pixels = new int[SIZE][SIZE]; - for (final int[] arr : this.pixels) { + // Callers write distinct pixels, so only the allocation needs the lock. + public void setPixel(final int x, final int z, final int color) { + int @Nullable [][] pixels = this.pixels; + if (pixels == null) { + pixels = this.allocatePixels(); + } + pixels[x & (SIZE - 1)][z & (SIZE - 1)] = color; + } + + private synchronized int[][] allocatePixels() { + int @Nullable [][] pixels = this.pixels; + if (pixels == null) { + pixels = new int[SIZE][SIZE]; + for (final int[] arr : pixels) { Arrays.fill(arr, Integer.MIN_VALUE); } + this.pixels = pixels; } - this.pixels[x & (SIZE - 1)][z & (SIZE - 1)] = color; + return pixels; } /**