ConcurrentCleaner.java
/*******************************************************************************
* Copyright (c) 2022 Eclipse RDF4J contributors.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Distribution License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: BSD-3-Clause
*******************************************************************************/
package org.eclipse.rdf4j.common.concurrent.locks.diagnostics;
import java.lang.ref.Cleaner;
import org.eclipse.rdf4j.common.annotation.InternalUseOnly;
/**
* Optimized for multithreaded use of the Java 9+ Cleaner
*
* @author H��vard M. Ottestad
*/
@InternalUseOnly
public class ConcurrentCleaner {
// Each Cleaner instance starts its own Thread, so we use a conservative maximum so as to not create too many
// threads.
private static final int MAX = 128;
private final static Cleaner[] cleaner;
private static final int mask;
static {
int concurrency = powerOfTwoSize(Runtime.getRuntime().availableProcessors() * 2);
mask = concurrency - 1;
cleaner = new Cleaner[concurrency];
}
private static int powerOfTwoSize(int initialSize) {
int n = -1 >>> Integer.numberOfLeadingZeros(initialSize - 1);
return (n < 0) ? 1 : (n >= MAX) ? MAX : n + 1;
}
static int getIndex(Thread key) {
if (key == null) {
return 0;
}
return mask & ((int) key.getId());
}
public Cleaner.Cleanable register(Object obj, Runnable action) {
Cleaner cleaner = ConcurrentCleaner.cleaner[getIndex(Thread.currentThread())];
if (cleaner == null) {
cleaner = instantiateCleaner(getIndex(Thread.currentThread()));
}
return cleaner.register(obj, action);
}
private synchronized static Cleaner instantiateCleaner(int index) {
if (ConcurrentCleaner.cleaner[index] == null) {
ConcurrentCleaner.cleaner[index] = Cleaner.create();
}
return ConcurrentCleaner.cleaner[index];
}
}