gpt4 book ai didi

java - 用 AtomicReference 代替 ReadWriteLock 来进行非阻塞操作

转载 作者:行者123 更新时间:2023-12-03 12:59:03 28 4
gpt4 key购买 nike

我写了这个类来重新加载 DataSource ,由整个应用程序使用,当持久化的配置数据发生变化时。
如您所见,它由 CDI 管理。并公开为 Singleton ,并且“配置更改”事件通过 configurationReload(...) 到达方法,但现在不相关。

引用更新由 ReentrantReadWriteLock 保护。 ,但我想知道是否需要它。

@Singleton
@ThreadSafe
class ReloadingDataSource implements DataSource {
private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
private final Lock readLock = readWriteLock.readLock();
private final Lock writeLock = readWriteLock.writeLock();

@GuardedBy("readWriteLock")
private DataSource delegateDataSource;

@Inject
ReloadingDataSource(@Nonnull final Configuration configuration) {
delegateDataSource = createDataSource(configuration);
}

private DataSource createDataSource(final Configuration configuration) {
... Create a ComboPooledDataSource using properties extracted from Configuration.
}

@Override
public Connection getConnection() throws SQLException {
readLock.lock();

try {
return delegateDataSource.getConnection();
} finally {
readLock.unlock();
}
}

...

private void configurationReload(
@Observes @Reload final ConfigurationChanged configurationChanged,
@Nonnull final Configuration configuration) {
final ConfigurationEvent event = configurationChanged.getConfigurationEvent();

if (event.getType() != AbstractFileConfiguration.EVENT_RELOAD && !event.isBeforeUpdate()) {
return;
}

writeLock.lock();

try {
destroyDelegateDataSource();
delegateDataSource = createDataSource(configuration);
} finally {
writeLock.unlock();
}
}

private void destroyDelegateDataSource() {
try {
DataSources.destroy(delegateDataSource);
} catch (final SQLException ignored) {
// Do nothing.
}
}
}

如果我们忽略创建新数据源的成本,上述策略是否可以替换为 AtomicReference<DataSource>? , 如下?
这将导致更好的性能和更容易阅读代码。

有没有更好的方法来处理这个我不知道的?
@Singleton
@ThreadSafe
class ReloadingDataSource implements DataSource {
private final AtomicReference<DataSource> delegateDataSource;

@Inject
ReloadingDataSource(@Nonnull final Configuration configuration) {
delegateDataSource = new AtomicReference<>(createDataSource(configuration));
}

private DataSource createDataSource(final Configuration configuration) {
... Create a ComboPooledDataSource using properties extracted from Configuration.
}

@Override
public Connection getConnection() throws SQLException {
return delegateDataSource.get().getConnection();
}

...

private void configurationReload(
@Observes @Reload final ConfigurationChanged configurationChanged,
@Nonnull final Configuration configuration) {
final ConfigurationEvent event = configurationChanged.getConfigurationEvent();

if (event.getType() != AbstractFileConfiguration.EVENT_RELOAD && !event.isBeforeUpdate()) {
return;
}

// Updated as per eckes tip. Is this what you meant?
final DataSource newDataSource = createDataSource(configuration);

while (true) {
final DataSource oldDataSource = delegateDataSource.get();

if (delegateDataSource.compareAndSet(oldDataSource, newDataSource)) {
destroyDelegateDataSource(oldDataSource);
break;
}
}
}

private void destroyDelegateDataSource(final DataSource oldDataSource) {
try {
DataSources.destroy(oldDataSource);
} catch (final SQLException ignored) {
// Do nothing.
}
}
}

最佳答案

如果您需要以有序的方式处理更新,您仍然需要锁定 reload 方法。在这种情况下,您可以放弃 AtomicReference 逻辑而只使用 volatile:

public class RDS {
private volatile DataSource delegate;

public Connection getConnection() throws SQLException {
return delegate.getConnection();
}

private void reload(Configuration config) {
DataSource old = null;
synchronized(this) {
old = delegate;
delegate = createDataSource(config);
}
destroyDataSource(old);
}
}

但是请注意,您仍然可能遇到其他问题,当您关闭旧 DataSource 时,连接可能仍在使用中(在@eckes 对该问题的第一条评论中提到)。为了解决这个问题,您需要一个类似于具有获取/释放类型逻辑的连接池之类的东西,一旦所有现有连接都被释放,它就会关闭旧委托(delegate)。

关于java - 用 AtomicReference 代替 ReadWriteLock 来进行非阻塞操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52707808/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com