or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

concurrent-histograms.mdcore-operations.mddouble-histograms.mdindex.mditerators.mdrecorders.mdserialization.mdspecialized-variants.mdutilities.md

concurrent-histograms.mddocs/

0

# Concurrent Histogram Variants

1

2

Thread-safe histogram implementations providing different levels of concurrency support for multi-threaded environments. Each variant offers distinct trade-offs between performance, thread safety guarantees, and feature support.

3

4

## AtomicHistogram

5

6

Lock-free, wait-free histogram using atomic operations for count updates. Provides thread-safe recording with limited synchronization for other operations.

7

8

```java { .api }

9

public class AtomicHistogram extends Histogram {

10

11

// Constructors

12

public AtomicHistogram(long highestTrackableValue, int numberOfSignificantValueDigits);

13

public AtomicHistogram(long lowestDiscernibleValue,

14

long highestTrackableValue,

15

int numberOfSignificantValueDigits);

16

public AtomicHistogram(AbstractHistogram source);

17

18

// Factory methods

19

static AtomicHistogram decodeFromByteBuffer(ByteBuffer buffer,

20

long minBarForHighestTrackableValue);

21

static AtomicHistogram decodeFromCompressedByteBuffer(ByteBuffer buffer,

22

long minBarForHighestTrackableValue);

23

static AtomicHistogram fromString(String base64CompressedHistogramString);

24

25

// Implementation methods

26

public AtomicHistogram copy();

27

public AtomicHistogram copyCorrectedForCoordinatedOmission(long expectedInterval);

28

}

29

```

30

31

### Thread Safety Characteristics

32

33

**Thread-Safe Operations:**

34

- `recordValue()` - Wait-free atomic recording

35

- `recordValueWithCount()` - Wait-free atomic recording

36

- `recordValueWithExpectedInterval()` - Wait-free atomic recording

37

38

**NOT Thread-Safe Operations:**

39

- Auto-resizing operations

40

- Value shifting operations

41

- Iteration operations

42

- Statistical queries (use external synchronization)

43

44

### Usage Examples

45

46

```java

47

// Create atomic histogram (no auto-resize support)

48

AtomicHistogram histogram = new AtomicHistogram(1_000_000, 3);

49

50

// Thread-safe recording from multiple threads

51

// Thread 1

52

new Thread(() -> {

53

for (int i = 0; i < 10000; i++) {

54

histogram.recordValue(ThreadLocalRandom.current().nextInt(1000));

55

}

56

}).start();

57

58

// Thread 2

59

new Thread(() -> {

60

for (int i = 0; i < 10000; i++) {

61

histogram.recordValue(ThreadLocalRandom.current().nextInt(2000));

62

}

63

}).start();

64

65

// Reading requires external synchronization

66

synchronized (histogram) {

67

long count = histogram.getTotalCount();

68

double mean = histogram.getMean();

69

long p95 = histogram.getValueAtPercentile(95.0);

70

}

71

```

72

73

### Performance Characteristics

74

75

- **Recording**: Wait-free, no contention between recording threads

76

- **Memory**: Atomic operations may have cache coherency overhead

77

- **Scalability**: Excellent for high-frequency recording scenarios

78

- **Limitations**: Fixed size (no auto-resize), queries need synchronization

79

80

## ConcurrentHistogram

81

82

Fully thread-safe histogram supporting concurrent recording, auto-resizing, and value shifting operations using writer-reader phasing.

83

84

```java { .api }

85

public class ConcurrentHistogram extends Histogram {

86

87

// Constructors

88

public ConcurrentHistogram(int numberOfSignificantValueDigits);

89

public ConcurrentHistogram(long highestTrackableValue, int numberOfSignificantValueDigits);

90

public ConcurrentHistogram(long lowestDiscernibleValue,

91

long highestTrackableValue,

92

int numberOfSignificantValueDigits);

93

public ConcurrentHistogram(AbstractHistogram source);

94

95

// Factory methods

96

static ConcurrentHistogram decodeFromByteBuffer(ByteBuffer buffer,

97

long minBarForHighestTrackableValue);

98

static ConcurrentHistogram decodeFromCompressedByteBuffer(ByteBuffer buffer,

99

long minBarForHighestTrackableValue);

100

static ConcurrentHistogram fromString(String base64CompressedHistogramString);

101

102

// Implementation methods

103

public ConcurrentHistogram copy();

104

public ConcurrentHistogram copyCorrectedForCoordinatedOmission(long expectedInterval);

105

}

106

```

107

108

### Auto-Resize Configuration

109

110

ConcurrentHistogram automatically enables auto-resize functionality and always sets auto-resize to true, regardless of the constructor used. This ensures that the histogram can dynamically expand to accommodate values outside its initial range without requiring manual configuration.

111

112

```java

113

// All ConcurrentHistogram instances have auto-resize enabled by default

114

ConcurrentHistogram histogram = new ConcurrentHistogram(3);

115

// Internal call: histogram.setAutoResize(true) - always executed

116

117

// Even if you try to disable it, it remains enabled

118

histogram.setAutoResize(false); // This call has no effect

119

assert histogram.isAutoResize() == true; // Always true for ConcurrentHistogram

120

```

121

122

### Thread Safety Characteristics

123

124

**Wait-Free/Lock-Free Operations:**

125

- `recordValue()` - Wait-free recording

126

- `recordValueWithCount()` - Wait-free recording

127

- `recordValueWithExpectedInterval()` - Wait-free recording

128

- Auto-resizing during recording

129

- Value shifting operations

130

131

**Requires External Synchronization:**

132

- Queries and statistical operations

133

- Iteration operations

134

- Histogram manipulation (`add()`, `subtract()`, etc.)

135

136

### Usage Examples

137

138

```java

139

// Create concurrent histogram with auto-resize support

140

ConcurrentHistogram histogram = new ConcurrentHistogram(3);

141

142

// Multiple threads can record concurrently without synchronization

143

ExecutorService executor = Executors.newFixedThreadPool(10);

144

145

for (int t = 0; t < 10; t++) {

146

executor.submit(() -> {

147

Random random = new Random();

148

for (int i = 0; i < 100000; i++) {

149

// No synchronization needed for recording

150

histogram.recordValue(random.nextInt(10000));

151

}

152

});

153

}

154

155

// Auto-resizing works concurrently

156

histogram.recordValue(Long.MAX_VALUE / 4); // Will auto-resize if needed

157

158

// Queries still need external synchronization

159

synchronized (histogram) {

160

histogram.outputPercentileDistribution(System.out, 1.0);

161

}

162

163

executor.shutdown();

164

```

165

166

### Writer-Reader Phasing

167

168

ConcurrentHistogram uses a writer-reader phaser for coordination:

169

170

```java

171

// Example of coordinated reading

172

WriterReaderPhaser phaser = histogram.getWriterReaderPhaser();

173

phaser.readerLock();

174

try {

175

// Safe to iterate or perform complex queries

176

for (HistogramIterationValue value : histogram.recordedValues()) {

177

System.out.println("Value: " + value.getValueIteratedTo() +

178

", Count: " + value.getCountAtValueIteratedTo());

179

}

180

} finally {

181

phaser.readerUnlock();

182

}

183

```

184

185

## SynchronizedHistogram

186

187

Fully thread-safe histogram with synchronized access for all operations. All methods are atomic with respect to modifications.

188

189

```java { .api }

190

public class SynchronizedHistogram extends Histogram {

191

192

// Constructors

193

public SynchronizedHistogram(int numberOfSignificantValueDigits);

194

public SynchronizedHistogram(long highestTrackableValue, int numberOfSignificantValueDigits);

195

public SynchronizedHistogram(long lowestDiscernibleValue,

196

long highestTrackableValue,

197

int numberOfSignificantValueDigits);

198

public SynchronizedHistogram(AbstractHistogram source);

199

200

// Factory methods

201

static SynchronizedHistogram decodeFromByteBuffer(ByteBuffer buffer,

202

long minBarForHighestTrackableValue);

203

static SynchronizedHistogram decodeFromCompressedByteBuffer(ByteBuffer buffer,

204

long minBarForHighestTrackableValue);

205

206

// Implementation methods

207

public SynchronizedHistogram copy();

208

public SynchronizedHistogram copyCorrectedForCoordinatedOmission(long expectedInterval);

209

}

210

```

211

212

### Thread Safety Characteristics

213

214

**Fully Synchronized Operations:**

215

- All operations are synchronized on the histogram instance

216

- Recording operations may block other operations

217

- Queries are consistent with concurrent modifications

218

- All histogram manipulation operations are thread-safe

219

220

### Usage Examples

221

222

```java

223

// Create synchronized histogram

224

SynchronizedHistogram histogram = new SynchronizedHistogram(3);

225

226

// All operations are thread-safe but may block

227

Runnable recorder = () -> {

228

for (int i = 0; i < 10000; i++) {

229

histogram.recordValue(i); // Thread-safe but blocking

230

}

231

};

232

233

Runnable analyzer = () -> {

234

while (true) {

235

// Thread-safe queries - no external synchronization needed

236

long count = histogram.getTotalCount();

237

double mean = histogram.getMean();

238

long p99 = histogram.getValueAtPercentile(99.0);

239

240

System.out.printf("Count: %d, Mean: %.2f, P99: %d%n", count, mean, p99);

241

242

try { Thread.sleep(1000); } catch (InterruptedException e) { break; }

243

}

244

};

245

246

// Start concurrent operations

247

new Thread(recorder).start();

248

new Thread(recorder).start();

249

new Thread(analyzer).start();

250

251

// Complex operations are also thread-safe

252

SynchronizedHistogram other = new SynchronizedHistogram(3);

253

other.recordValue(1000);

254

histogram.add(other); // Thread-safe histogram addition

255

```

256

257

## Concurrency Comparison

258

259

| Feature | AtomicHistogram | ConcurrentHistogram | SynchronizedHistogram |

260

|---------|----------------|-------------------|---------------------|

261

| Recording Performance | Excellent (wait-free) | Excellent (wait-free) | Good (blocking) |

262

| Auto-resize Support | No | Yes | Yes |

263

| Value Shifting | No | Yes | Yes |

264

| Query Thread Safety | External sync needed | External sync needed | Built-in |

265

| Memory Overhead | Low | Medium (phaser) | Low |

266

| Use Case | High-frequency recording | Full concurrent features | Simple thread safety |

267

268

## Choosing the Right Variant

269

270

### Use AtomicHistogram When:

271

- High-frequency recording from multiple threads

272

- Fixed value range is acceptable

273

- Reading/analysis happens infrequently with controlled synchronization

274

- Maximum recording performance is critical

275

276

```java

277

// High-frequency latency recording

278

AtomicHistogram latencyHist = new AtomicHistogram(10_000_000, 3); // Max 10s latency

279

280

// Multiple producer threads

281

producers.forEach(producer ->

282

producer.onLatencyMeasured(latency -> latencyHist.recordValue(latency))

283

);

284

285

// Periodic analysis with synchronization

286

scheduledExecutor.scheduleAtFixedRate(() -> {

287

synchronized (latencyHist) {

288

analyzeLatencyDistribution(latencyHist);

289

}

290

}, 0, 10, TimeUnit.SECONDS);

291

```

292

293

### Use ConcurrentHistogram When:

294

- Need full concurrent feature support

295

- Auto-resizing is required

296

- Value shifting operations are needed

297

- Can coordinate reading/analysis phases

298

299

```java

300

// Auto-resizing concurrent histogram for varying workloads

301

ConcurrentHistogram responseTime = new ConcurrentHistogram(3);

302

303

// Multiple threads recording different ranges

304

recordingThreads.forEach(thread ->

305

thread.onResponse(time -> responseTime.recordValue(time))

306

);

307

308

// Coordinated analysis

309

WriterReaderPhaser phaser = responseTime.getWriterReaderPhaser();

310

phaser.readerLock();

311

try {

312

generateReport(responseTime);

313

} finally {

314

phaser.readerUnlock();

315

}

316

```

317

318

### Use SynchronizedHistogram When:

319

- Simple thread safety is preferred over performance

320

- Frequent queries from multiple threads

321

- Blocking behavior is acceptable

322

- Easy integration with existing synchronized code

323

324

```java

325

// Simple thread-safe histogram for mixed read/write workloads

326

SynchronizedHistogram requestSize = new SynchronizedHistogram(3);

327

328

// Recording thread

329

requestHandler.onRequest(req -> requestSize.recordValue(req.getSize()));

330

331

// Monitoring threads can query safely

332

monitoringThreads.forEach(monitor ->

333

monitor.scheduleReporting(() -> {

334

// No synchronization needed

335

double avgSize = requestSize.getMean();

336

long p95Size = requestSize.getValueAtPercentile(95.0);

337

reportMetrics(avgSize, p95Size);

338

})

339

);

340

```

341

342

## Performance Considerations

343

344

### AtomicHistogram Performance

345

- **Best** for recording-heavy workloads

346

- Cache line contention possible with many threads

347

- Consider using multiple histograms and merging periodically

348

349

### ConcurrentHistogram Performance

350

- Writer-reader phaser adds coordination overhead

351

- Excellent scaling for mixed read/write workloads

352

- Auto-resize may cause temporary pauses

353

354

### SynchronizedHistogram Performance

355

- Simplest implementation but may limit scalability

356

- Good for lower-frequency operations

357

- Contention increases with thread count

358

359

## Memory Models and Visibility

360

361

All concurrent variants provide proper memory visibility guarantees:

362

- Recorded values are visible across threads

363

- Statistical queries reflect all recorded values up to the query point

364

- No additional memory barriers needed for basic usage