privatefinalboolean PRINT_TIMES = false; // False for use as run test.
// Number of increments done by each thread. Must be multiple of largest hold time below, // times any possible thread count. We reduce this below if PRINT_TIMES is not set, and // even more in debuggable mode. privatefinalint UNSCALED_TOTAL_ITERS = 16_000_000; privatefinalint UNSCALED_MAX_HOLD_TIME = 2_000_000; privateint totalIters; privateint maxHoldTime;
privateint counter;
private AtomicInteger atomicCounter = new AtomicInteger();
private Object lock;
privateint currentThreadCount = 0;
privatestaticboolean debuggable = false; // Running in a debuggable ART environment.
// A function such that if we repeatedly apply it to -1, the value oscillates // between -1 and 3. Thus the average value is 1. // This is designed to make it hard for the compiler to predict the values in // the sequence. privateint nextInt(int x) { if (x < 0) { return x * x + 2;
} else { return x - 4;
}
}
// Increment counter by n, holding lock for time roughly propertional to n. // N must be even. privatevoid holdFor(Object lock, int n) { synchronized(lock) { int y = -1; for (int i = 0; i < n; ++i) {
counter += y;
y = nextInt(y);
}
}
}
// Increment local by an even number n in a way that takes time roughly proportional // to n. privatevoid spinFor(int n) { int y = -1; int local_counter = 0; for (int i = 0; i < n; ++i) {
local_counter += y;
y = nextInt(y);
} if (local_counter != n) { thrownew Error();
}
}
privateclass RepeatedLockHolder implements Runnable {
RepeatedLockHolder(boolean shared, int n /* even */) {
sharedLock = shared;
holdTime = n;
}
@Override publicvoid run() {
Object myLock = sharedLock ? lock : new Object(); int nIters = totalIters / currentThreadCount / holdTime; for (int i = 0; i < nIters; ++i) {
holdFor(myLock, holdTime);
}
} privateboolean sharedLock; privateint holdTime;
}
privateclass RepeatedIntermittentLockHolder implements Runnable {
RepeatedIntermittentLockHolder(boolean shared, int n /* even */) {
sharedLock = shared;
holdTime = n;
}
@Override publicvoid run() {
Object myLock = sharedLock ? lock : new Object(); int iter_divisor = 10 * currentThreadCount * holdTime; int nIters = totalIters / iter_divisor; if (totalIters % iter_divisor != 0 || holdTime % 2 == 1) {
System.err.println("Misconfigured: totalIters = " + totalIters
+ " iter_divisor = " + iter_divisor);
} for (int i = 0; i < nIters; ++i) {
spinFor(9 * holdTime);
holdFor(myLock, holdTime);
}
} privateboolean sharedLock; privateint holdTime;
}
// Increment atomicCounter n times, on average by 1 each time. privateclass RepeatedIncrementer implements Runnable {
@Override publicvoid run() { int y = -1; int nIters = totalIters / currentThreadCount; for (int i = 0; i < nIters; ++i) {
atomicCounter.addAndGet(y);
y = nextInt(y);
}
}
}
// Run n threads doing work. Return the elapsed time this took, in milliseconds. privatelong runMultiple(int n, Runnable work) { Thread[] threads = newThread[n]; // Replace lock, so that we start with a clean, uninflated lock each time.
lock = new Object(); for (int i = 0; i < n; ++i) {
threads[i] = newThread(work);
} long startTime = System.currentTimeMillis(); for (int i = 0; i < n; ++i) {
threads[i].start();
} for (int i = 0; i < n; ++i) { try {
threads[i].join();
} catch(InterruptedException e) { thrownew AssertionError("Unexpected interrupt");
}
} return System.currentTimeMillis() - startTime;
}
// Run on different numbers of threads. privatevoid runAll(Runnable work, Runnable init, Runnable checker) { for (int i = 1; i <= 8; i *= 2) {
currentThreadCount = i;
init.run(); long time = runMultiple(i, work); if (PRINT_TIMES) {
System.out.print(time + (i == 8 ? "\n" : "\t"));
}
checker.run();
}
}
privatevoid run() { int scale = PRINT_TIMES ? 1 : (debuggable ? 20 : 10);
totalIters = UNSCALED_TOTAL_ITERS / scale;
maxHoldTime = UNSCALED_MAX_HOLD_TIME / scale; if (PRINT_TIMES) {
System.out.println("All times in milliseconds for 1, 2, 4 and 8 threads");
}
System.out.println("Atomic increments");
runAll(new RepeatedIncrementer(), () -> { atomicCounter.set(0); }, new CheckAtomicCounter()); for (int i = 2; i <= UNSCALED_MAX_HOLD_TIME / 100; i *= 10) { // i * 8 (max thread count) divides totalIters
System.out.println("Hold time " + i + ", shared lock");
runAll(new RepeatedLockHolder(true, i), () -> { counter = 0; }, new CheckCounter(totalIters));
} for (int i = 2; i <= UNSCALED_MAX_HOLD_TIME / 1000; i *= 10) { // i * 8 (max thread count) divides totalIters
System.out.println("Hold time " + i + ", pause time " + (9 * i) + ", shared lock");
runAll(new RepeatedIntermittentLockHolder(true, i), () -> { counter = 0; }, new CheckCounter(totalIters / 10));
} if (PRINT_TIMES) { for (int i = 2; i <= maxHoldTime; i *= 1000) { // i divides totalIters
System.out.println("Hold time " + i + ", private lock"); // Since there is no mutual exclusion final counter value is unpredictable.
runAll(new RepeatedLockHolder(false, i), () -> { counter = 0; }, () -> {});
}
}
System.out.println("Hold for 2 msecs while sleeping, shared lock");
runAll(new SleepyLockHolder(true), () -> { counter = 0; }, new CheckCounter(totalIters));
System.out.println("Hold for 2 msecs while sleeping, private lock");
runAll(new SleepyLockHolder(false), () -> { counter = 0; }, () -> {});
}
publicstaticvoid main(String[] args) { if (System.getProperty("java.vm.name").equalsIgnoreCase("Dalvik")) { try {
System.loadLibrary(args[0]);
debuggable = isDebuggable();
} catch (Throwable t) { // Conservatively assume we might be debuggable, and pretend we loaded the library. // As of June 2024, we seem to get here with atest.
debuggable = true;
System.out.println("JNI_OnLoad called");
}
} else {
System.out.println("JNI_OnLoad called"); // Not really, but match expected output.
}
System.out.println("Starting"); new Main().run();
}
privatestaticnativeboolean isDebuggable();
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.1 Sekunden
(vorverarbeitet am 2026-06-29)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.