Java-Leistungsoptimierung: Acht Anti-Patterns, die Ihren Code verlangsamen

✍️ OpenClawRadar📅 Veröffentlicht: 20. März 2026🔗 Source
Java-Leistungsoptimierung: Acht Anti-Patterns, die Ihren Code verlangsamen
Ad

Leistungsverbesserungen durch die Behebung von Anti-Patterns

Jonathan Vogel entwickelte eine Java-Bestellverarbeitungs-App, die anfangs eine Laufzeit von 1.198 ms hatte, 85.000 Bestellungen pro Sekunde verarbeitete, etwas mehr als 1 GB Heap verwendete und 19 GC-Pausen aufwies. Nach der Behebung von acht Anti-Patterns ohne Architekturänderungen oder JDK-Updates verbesserte sich die Leistung auf 239 ms Laufzeit, 419.000 Bestellungen pro Sekunde, 139 MB Heap und 4 GC-Pausen. Dies entspricht einer 5-fachen Durchsatzsteigerung, 87 % weniger Heap-Verbrauch und 79 % weniger GC-Pausen.

Acht Java-Leistungs-Anti-Patterns, die behoben werden sollten

  • String-Verkettung in Schleifen - O(n²) Kopiervorgänge aufgrund von Unveränderlichkeit
  • O(n²) Stream-Iteration innerhalb von Schleifen - Streamen der gesamten Liste pro Element
  • String.format() in Hot Paths - Langsamster String-Builder, parst Format bei jedem Aufruf
  • Autoboxing in Hot Paths - Millionen von Wegwerf-Wrapper-Objekten
  • Exceptions für Kontrollfluss - fillInStackTrace() durchläuft den gesamten Aufrufstack
  • Zu breite Synchronisierung - Eine Sperre wird zum Engpass
  • Wiederverwendbare Objekte neu erstellen - ObjectMapper, DateTimeFormatter, Gson pro Aufruf
  • Virtual Thread Pinning (JDK 21-23) - Synchronisiert + blockierende I/O blockiert Carrier
Ad

Detaillierte Beispiele und Lösungen

1. String-Verkettung in Schleifen

Problemcode:

String report = "";
for (String line : logLines) {
    report = report + line + "\n";
}

Dies erzeugt O(n²) Kopiervorgänge aufgrund der Unveränderlichkeit von Strings. BellSoft JMH Benchmarks zeigen, dass bei einer 4-fachen Vergrößerung von n die Schleifenverkettung um mehr als das 7-fache langsamer wird.

Lösung:

StringBuilder sb = new StringBuilder();
for (String line : logLines) {
    sb.append(line).append("\n");
}
String report = sb.toString();

Hinweis: Seit JDK 9 optimiert der Compiler Einzeilen-Verkettungen wie "Order: " + id + " total: " + amount, aber diese Optimierung gilt nicht für Schleifen.

2. Versehentliches O(n²) mit Streams in Schleifen

Problemcode:

for (Order order : orders) {
    int hour = order.timestamp().atZone(ZoneId.systemDefault()).getHour();
    long countForHour = orders.stream()
        .filter(o -> o.timestamp().atZone(ZoneId.systemDefault()).getHour() == hour)
        .count();
    ordersByHour.put(hour, countForHour);
}

Dieses Muster machte fast 71 % der CPU-Stack-Samples in der JFR-Aufzeichnung aus. Bei 10.000 Bestellungen führt es 100 Millionen Vergleiche anstelle eines einzigen Durchlaufs durch.

Lösung:

for (Order order : orders) {
    int hour = order.timestamp().atZone(ZoneId.systemDefault()).getHour();
    ordersByHour.merge(hour, 1L, Long::sum);
}

Dies bietet O(n)-Leistung mit einem Durchlauf. Man könnte auch Collectors.groupingBy(... Collectors.counting()) in einer einzigen Stream-Pipeline verwenden.

Der Artikel ist Teil 1 einer 3-teiligen Serie zur Java-Leistungsoptimierung, wobei die Teile 2 und 3 bald folgen. Teil 2 wird die Profiling-Daten hinter diesen Zahlen durchgehen, einschließlich Flame-Graphs und welche Methoden tatsächlich Hot waren.

📖 Read the full source: HN AI Agents

Ad

👀 Siehe auch