org.postgresql.util.SharedTimer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jdbc-yugabytedb Show documentation
Show all versions of jdbc-yugabytedb Show documentation
Java JDBC 4.2 (JRE 8+) driver for YugaByte SQL database
The newest version!
/*
* Copyright (c) 2004, PostgreSQL Global Development Group
* See the LICENSE file in the project root for more information.
*/
package org.postgresql.util;
import org.postgresql.jdbc.ResourceLock;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.Timer;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
public class SharedTimer {
static class TimerCleanup implements LazyCleaner.CleaningAction {
private final Timer timer;
TimerCleanup(Timer timer) {
this.timer = timer;
}
@Override
public void onClean(boolean leak) throws RuntimeException {
timer.cancel();
}
}
// Incremented for each Timer created, this allows each to have a unique Timer name
private static final AtomicInteger timerCount = new AtomicInteger(0);
private static final Logger LOGGER = Logger.getLogger(SharedTimer.class.getName());
private volatile @Nullable Timer timer;
private final AtomicInteger refCount = new AtomicInteger(0);
private final ResourceLock lock = new ResourceLock();
private LazyCleaner.@Nullable Cleanable timerCleanup;
public SharedTimer() {
}
public int getRefCount() {
return refCount.get();
}
public Timer getTimer() {
try (ResourceLock ignore = lock.obtain()) {
Timer timer = this.timer;
if (timer == null) {
int index = timerCount.incrementAndGet();
/*
Temporarily switch contextClassLoader to the one that loaded this driver to avoid TimerThread preventing current
contextClassLoader - which may be the ClassLoader of a web application - from being GC:ed.
*/
final ClassLoader prevContextCL = Thread.currentThread().getContextClassLoader();
try {
/*
Scheduled tasks should not need to use .getContextClassLoader, so we just reset it to null
*/
Thread.currentThread().setContextClassLoader(null);
this.timer = timer = new Timer("PostgreSQL-JDBC-SharedTimer-" + index, true);
this.timerCleanup = LazyCleaner.getInstance().register(refCount, new TimerCleanup(timer));
} finally {
Thread.currentThread().setContextClassLoader(prevContextCL);
}
}
refCount.incrementAndGet();
return timer;
}
}
public void releaseTimer() {
try (ResourceLock ignore = lock.obtain()) {
int count = refCount.decrementAndGet();
if (count > 0) {
// There are outstanding references to the timer so do nothing
LOGGER.log(Level.FINEST, "Outstanding references still exist so not closing shared Timer");
} else if (count == 0) {
// This is the last usage of the Timer so cancel it so it's resources can be release.
LOGGER.log(Level.FINEST, "No outstanding references to shared Timer, will cancel and close it");
if (timerCleanup != null) {
timerCleanup.clean();
timer = null;
timerCleanup = null;
}
} else {
// Should not get here under normal circumstance, probably a bug in app code.
LOGGER.log(Level.WARNING,
"releaseTimer() called too many times; there is probably a bug in the calling code");
refCount.set(0);
}
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy