今日已更新 412 条资讯 | 累计 19972 条内容
关于我们

标签:#Concurrency

找到 6 篇相关文章

开发者

Cloudflare Identifies Race Condition in hyper’s HTTP/1 Implementation

Cloudflare recently documented how its development team identified and fixed a rare bug in the widely used Rust HTTP library hyper that could silently truncate large HTTP responses while still returning a successful 200 OK status. The issue had existed for years, was triggered only under specific timing conditions, and has now been fixed upstream. By Renato Losio

2026-07-12 原文 →
AI 资讯

Your Loom App Quietly Became a Thread Pool Again: A Field Guide to Virtual Thread Pinning

The incident that taught me to respect pinning looked like nothing. A service freshly migrated to virtual threads, a load test that plateaued at about 420 requests per second no matter how much traffic we threw at it, CPU sitting at 9%, zero errors, zero warnings, nothing in the logs. The machine had 8 cores, and the one downstream HTTP call in the hot path took about 19 ms. Do the arithmetic: 8 × (1000 / 19) ≈ 421. The service that was supposed to scale to millions of virtual threads was serving exactly one request per CPU core. Loom had quietly handed us back a bounded thread pool, and the code looked perfectly innocent. That failure mode has a name — pinning — and this is the field guide I wish I'd had that night: what it is, the two (and only two) things that cause it, what JDK 24 changed, and how to catch it before your throughput graph does. What pinning actually is A virtual thread doesn't own an OS thread. It runs on a small pool of platform threads called carrier threads — concretely, the workers of a dedicated ForkJoinPool living in a thread group named CarrierThreads , with default parallelism equal to Runtime.availableProcessors() . When a virtual thread blocks — on I/O, a lock, a queue — it normally unmounts : it saves its stack, steps off the carrier, and frees that carrier to run another virtual thread. That unmount is the entire trick that lets a handful of OS threads serve millions of virtual ones. Pinning is when the unmount can't happen. The virtual thread blocks but stays mounted, and its carrier sits there doing nothing useful for the whole duration. One pinned carrier is a rounding error. But the default carrier pool is only as big as your core count, so if a hot path pins routinely, you pin every carrier at once — and then no virtual thread anywhere makes progress. That's not a slowdown; it's scheduler starvation, and from the outside it looks a lot like a deadlock. You can raise the ceiling with -Djdk.virtualThreadScheduler.parallelism=N , bu

2026-07-11 原文 →
AI 资讯

Deadlock — Deadlock Detection

Deadlock detection: vì sao Postgres chỉ dò cycle sau deadlock_timeout , và vì sao retry mù làm vỡ thêm Deadlock xảy ra khi hai (hoặc nhiều) transaction đang giữ lock mà bên kia cần, tạo thành một vòng tròn đợi không thoát ra được nếu không có trọng tài. Postgres là trọng tài đó: nó dựng wait-for graph từ trạng thái lock hiện tại, phát hiện cycle, và chủ động abort một transaction để cắt vòng. Dev gặp class lỗi này không phải vì viết code "sai" mà vì hai code path đụng cùng tài nguyên theo thứ tự khác nhau dưới load cao — ở môi trường dev một mình thì không thấy, lên production concurrent đủ thì ERROR: deadlock detected (SQLSTATE 40P01 ) ném ra, một transaction bị rollback, request user trả 500. Hậu quả nặng nhất không phải bản thân deadlock, mà là retry layer viết kiểu "cứ lỗi thì retry vô hạn": cùng pattern lock sai thứ tự, cùng tạo lại cycle, deadlock counter tăng tuyến tính với traffic, log Postgres ngập, và database CPU bị burn vào việc chạy graph algorithm thay vì việc thật. Cơ chế hoạt động Postgres không dò deadlock liên tục. Mỗi lần một backend phải đợi lock, nó đăng ký với lock manager và đi ngủ; chỉ khi ngủ vượt deadlock_timeout (mặc định 1 giây, GUC ở runtime-config-locks ), backend đó mới được đánh thức để chạy thuật toán dò cycle. Đây là quyết định thiết kế nêu trong Postgres docs về Lock Management: phần lớn lock chờ trong workload bình thường chỉ kéo dài vài ms (chờ một UPDATE ngắn commit) — chạy graph algorithm trên mọi lần lock-wait sẽ tốn CPU vô ích. Lazy detection đánh đổi: nếu có cycle thật, mọi transaction trong cycle treo ít nhất deadlock_timeout trước khi được giải phóng. Khi timer kích hoạt, backend đó dựng wait-for graph từ lock manager: với mỗi process đang đợi lock, vẽ một cạnh hướng từ "process đợi" sang "process giữ lock đó". Postgres còn phải xử lý lock soft-conflict (hai process cùng đợi, không ai giữ — nếu được sắp xếp lại thứ tự thì cả hai đều chạy được mà không cần kill ai); thuật toán thật trong deadlock.c (source tree Postgres) th

2026-07-07 原文 →
AI 资讯

Lock Manager — Lock Overview

Lock trong Postgres: hai tầng heavyweight/lightweight, vì sao một ALTER đứng yên kéo theo cả service Postgres chia khoá thành hai tầng chạy song song. Heavyweight lock (Postgres docs gọi là "regular locks" hay table-level/row-level lock) giữ vai trò bảo vệ object logic — relation, tuple, transactionid — sống suốt một transaction, hiện ra trong view pg_locks và là loại mà application code "thấy" được. Lightweight lock (LWLock) bảo vệ các vùng nhớ chia sẻ bên trong server — buffer descriptor, WAL insert position, hash table của chính lock manager — chỉ ôm trong thời gian rất ngắn, không hiện trong pg_locks nhưng lộ ra qua wait_event_type = 'LWLock' ở pg_stat_activity . Hai tầng có hai cơ chế chờ khác nhau, hai loại sự cố production khác nhau, và nếu chỉ "biết row lock" thì sẽ bỏ qua hai class incident kinh điển: một ALTER TABLE đứng đợi ACCESS EXCLUSIVE làm đông cứng mọi SELECT đến sau nó, và LockManager partition LWLock thành điểm nghẽn khi đụng nhiều partition trong một query. Cơ chế hoạt động Heavyweight lock được quản lý bằng một hash table trong shared memory, chia thành nhiều partition để giảm contention (số partition là NUM_LOCK_PARTITIONS , set tại compile time). Mỗi entry ứng với một (locktag, mode) ; locktag là tuple (locktype, database, relation, ...) nhận diện object cần khoá. Tám lock mode trên relation chia thành ma trận xung đột cố định: ACCESS SHARE (cấp bởi SELECT ) xung đột duy nhất với ACCESS EXCLUSIVE (cấp bởi DROP TABLE , TRUNCATE , hầu hết ALTER TABLE , REINDEX , CLUSTER ); ROW EXCLUSIVE (cấp bởi INSERT / UPDATE / DELETE ) xung đột với SHARE trở lên; SHARE UPDATE EXCLUSIVE (cấp bởi VACUUM không-FULL, ANALYZE , CREATE INDEX CONCURRENTLY ) tự xung đột với chính nó — đó là lý do chỉ một autovacuum hoặc một CREATE INDEX CONCURRENTLY chạy mỗi lần trên cùng bảng. Ma trận này nằm trong docs Postgres mục Explicit Locking và là kiến thức nền cho mọi quyết định migration online. -- xem mode đang giữ trên một bảng SELECT pid , mode , granted , locktype , re

2026-07-07 原文 →
开发者

Stop Leaking Trace Context: How to Migrate OpenTelemetry to JDK 26 Scoped Values

Stop Leaking Trace Context: How to Migrate OpenTelemetry to JDK 26 Scoped Values If you are still relying on traditional ThreadLocal storage for OpenTelemetry context propagation under JDK 26's virtual threads, you are sitting on a production time bomb. Millions of concurrent virtual threads will quickly turn your heap into a graveyard of leaked trace contexts and bloated memory overhead. If you're prepping for interviews, I've been building javalld.com — real machine coding problems with full execution traces. Why Most Developers Get This Wrong Defaulting to ThreadLocal: Assuming the default OpenTelemetry ThreadLocal storage works fine with virtual threads, ignoring the heavy heap footprint and context drift when threads are unmounted and rescheduled. Ignoring Context Leakage: Forgetting that ThreadLocal values persist unless explicitly removed, causing trace data to bleed into unrelated tasks on shared carrier threads. Manual Propagation Mess: Manually passing Span objects down the call stack instead of leveraging JDK 26's native scoped value propagation. The Right Way The clean solution is to bind OpenTelemetry's ContextStorage directly to JEP 487 Scoped Values to enforce immutable, automatic, and thread-safe context propagation across virtual threads and structured concurrency boundaries. Implement Custom ContextStorage: Create an OTel ContextStorage implementation backed by a static ScopedValue<Context> . Enforce Immutability: Leverage the immutable nature of ScopedValue to prevent downstream child threads from accidentally mutating the parent's tracing context. Leverage Structured Concurrency: Use StructuredTaskScope which automatically inherits the scoped trace context without manual boilerplate. Show Me The Code Here is how to run a span using JDK 26 ScopedValue for zero-leak, zero-overhead propagation: public class ScopedTraceRunner { private static final ScopedValue < Span > ACTIVE_SPAN = ScopedValue . newInstance (); public void execute ( Span span , Runn

2026-06-05 原文 →
AI 资讯

Java LLD: Designing a Thread-Safe Parking Lot with Strategy Pattern

Java LLD: Designing a Thread-Safe Parking Lot with Strategy Pattern Designing a parking lot is a staple of Java LLD and machine coding interviews, yet most candidates fail to write production-grade code. As an ex-FAANG interviewer, I've seen countless designs fall apart under concurrent traffic or when asked to support multiple slot allocation algorithms. If you're prepping for interviews, I've been building javalld.com — real machine coding problems with full execution traces. The Mistake Most Candidates Make Monolithic locking on the entire ParkingLot class: Using a global synchronized keyword on the entry method, which serializes all gate entries and destroys system throughput. Hardcoding slot-finding logic: Mixing spatial layout algorithms (like nearest-to-entrance or smallest-available-fit) directly inside the ParkingLot or Gate classes, violating the Open-Closed Principle. Thread-safety as an afterthought: Relying on raw List<Slot> iterations without synchronization, causing race conditions where multiple cars are assigned to the exact same physical slot. The Right Approach Core mental model: Decouple capacity management from slot selection by using a Semaphore for gate-keeping and the Strategy Pattern for thread-safe slot allocation. Key entities: ParkingLot , Gate , Slot , Vehicle , ParkingStrategy ( SmallestFitStrategy , NearestEntranceStrategy ), and StrategyFactory . Why it beats the naive approach: It isolates concurrency concerns (preventing overbooking) from business rules (how we choose a slot), making the system highly performant and easily extensible. The Key Insight (Code) public class EntryGate { private final Semaphore semaphore ; private final ParkingStrategy strategy ; public EntryGate ( int capacity , ParkingStrategy strategy ) { this . semaphore = new Semaphore ( capacity ); this . strategy = strategy ; } public synchronized Ticket park ( Vehicle vehicle ) { if (! semaphore . tryAcquire ()) throw new ParkingFullException (); Slot slot = strat

2026-05-29 原文 →