gpt4 book ai didi

Java,创建可重用线程不安全对象的缓存

转载 作者:行者123 更新时间:2023-12-01 18:46:22 26 4
gpt4 key购买 nike

有时在java中我有一些线程不安全且创建成本昂贵的对象。我想创建这些对象的缓存,这样我就不需要重新创建它们,但它还必须防止对同一对象的并发访问。

例如,我可能有 DateFormat 并且创建它的成本太高,但我无法共享单个 DateFormat。为了论证,假设我不能使用线程安全的 DateFormat

如果能够创建像这样的缓存,那就太棒了:

Cache<DateFormat> cache = new Cache(() -> dateFormatCreator());
// and now make use of a dateFormat that might be created for this call
// or it might be an existing one from the cache.
cache.withExclusiveAccessToObject(dateFormat -> {
// use the dateFormat here, it is not in use by any other thread at the same time.
// new dateFormats can be created on the fly as needed.
});

我还应该提到 ThreadLocal 并不理想,因为我无法确保线程将被重用。

最佳答案

我相信有两条路可以走:

选项 1

维护每个线程一个对象

如果您从一组有限的明确定义的线程访问昂贵的对象(请阅读,使用线程池而不是每次都创建线程,这在许多应用程序中无论如何都会发生),那么这可以工作。

在这种情况下,您可以使用ThreadLocal。由于在一个线程中,所有内容都应该是连续的,因此您可以将线程不安全的对象保留在线程本地中。

您可以将 ThreadLocal 视为每个线程维护一个昂贵对象的专用实例的映射。

选项 2

在 M 个线程之间共享一个(或者通常是 N 个)对象,使得 N < M。在这种情况下,可能会出现两个线程尝试使用同一个对象的情况。

我不知道有现成的解决方案,毕竟它是您想要维护的对象,但一般来说,包装您自己的实现非常容易,该实现将提供对对象的某种锁定/同步访问您的对象类型。

实现的想法范围可能会有所不同。作为一个想法:您可以使用运行时/构建时生成的代理包装实际对象,使其有效地线程安全:

public interface IMyObject {
void inc();
void dec();
}

// this is an object that you would like to make thread safe
public class MyActualObject implements IMyObject {
private int counter = 0;
void inc() {counter++;}
void dec() {counter--;}
}

public class MyThreadSafeProxy implements IMyObject {

private IMyObject realObject;

public MyThreadSafeProxy(IMyObject realObject) {
this.realObject = realObject;
}

@Override
public synchronized void inc() {
realObject.inc();
}

@Override
public syncrhonized void dec() {
realObject.dec();
}
}

您可以将它们包装在 MyThreadSafeProxy 中,而不是存储 MyObject-s

也可以自动生成这样的代理:参见 cglib框架或 Dynamic Proxies (java.lang.Proxy class)

根据我的经验,通常选项 1 更可取,除非您使用的对象太昂贵,以至于如果池中有 N 个线程,您就无法真正支持内存中的 N 个对象。

关于Java,创建可重用线程不安全对象的缓存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59833708/

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