37 runnable examples covering the eight feature posts on ankurm.com, verified against Jackson 3.2.1 on Temurin 21.0.5. Every output committed under docs/ was produced by run-all.sh. Also documents 11 places where the published snippets do not compile or do not behave as printed against a real Jackson 3 build - most notably that writeValueAsString(List<Base>) silently drops the polymorphic type discriminator, so the post's serialised output cannot be read back.
70 lines
3.0 KiB
Java
70 lines
3.0 KiB
Java
package com.ankurm.jackson3.beyond;
|
|
|
|
import tools.jackson.core.json.JsonFactory;
|
|
import tools.jackson.core.util.JsonRecyclerPools;
|
|
import tools.jackson.core.util.RecyclerPool;
|
|
import tools.jackson.databind.json.JsonMapper;
|
|
|
|
import java.util.List;
|
|
import java.util.concurrent.Callable;
|
|
import java.util.concurrent.ExecutorService;
|
|
import java.util.concurrent.Executors;
|
|
|
|
/**
|
|
* BEYOND THE POSTS — the performance knob the comparison post names but never measures.
|
|
*
|
|
* Jackson 3 changed the default buffer RecyclerPool. The post says to restore the 2.x
|
|
* thread-local pool if you see a regression. Whether that helps depends entirely on your
|
|
* concurrency profile, so this measures it on the machine you are actually running on
|
|
* instead of asserting a winner.
|
|
*
|
|
* Indicative timings, not JMH. Run it a few times; the numbers move.
|
|
*/
|
|
public class Y06RecyclerPoolTuning {
|
|
|
|
public record Payload(long id, String name, List<String> tags, double amount) { }
|
|
|
|
private static final int ITERATIONS = 40_000;
|
|
|
|
public static void main(String[] args) throws Exception {
|
|
System.out.println("default pool : "
|
|
+ JsonRecyclerPools.defaultPool().getClass().getSimpleName());
|
|
System.out.println("cores : " + Runtime.getRuntime().availableProcessors());
|
|
System.out.println();
|
|
|
|
for (int threads : new int[] { 1, 8 }) {
|
|
System.out.println("--- " + threads + " thread(s), " + ITERATIONS + " round-trips each ---");
|
|
run(threads, "threadLocalPool (2.x default)", JsonRecyclerPools.threadLocalPool());
|
|
run(threads, "concurrentDeque (3.x default)", JsonRecyclerPools.newConcurrentDequePool());
|
|
run(threads, "nonRecyclingPool (no reuse) ", JsonRecyclerPools.nonRecyclingPool());
|
|
System.out.println();
|
|
}
|
|
}
|
|
|
|
private static void run(int threads, String label, RecyclerPool<?> pool) throws Exception {
|
|
@SuppressWarnings({ "unchecked", "rawtypes" })
|
|
JsonFactory factory = JsonFactory.builder().recyclerPool((RecyclerPool) pool).build();
|
|
JsonMapper mapper = JsonMapper.builder(factory).build();
|
|
|
|
Payload sample = new Payload(1L, "example", List.of("a", "b", "c"), 12.5);
|
|
for (int i = 0; i < 2_000; i++) { // warm up
|
|
mapper.readValue(mapper.writeValueAsString(sample), Payload.class);
|
|
}
|
|
|
|
ExecutorService pooled = Executors.newFixedThreadPool(threads);
|
|
long start = System.nanoTime();
|
|
var tasks = java.util.stream.IntStream.range(0, threads)
|
|
.<Callable<Void>>mapToObj(t -> () -> {
|
|
for (int i = 0; i < ITERATIONS; i++) {
|
|
mapper.readValue(mapper.writeValueAsString(sample), Payload.class);
|
|
}
|
|
return null;
|
|
}).toList();
|
|
for (var future : pooled.invokeAll(tasks)) future.get();
|
|
long ms = (System.nanoTime() - start) / 1_000_000;
|
|
pooled.shutdown();
|
|
|
|
System.out.printf(" %-34s %5d ms%n", label, ms);
|
|
}
|
|
}
|