gpt4 book ai didi

java - 设计 : Object with single use?

转载 作者:塔克拉玛干 更新时间:2023-11-02 08:10:51 26 4
gpt4 key购买 nike

上下文

我有一个名为 ImageLoader 的类。

当我调用 ImageLoader 的 getPicture( pictureID ) 时,如果图片没有被缓存,我将 pictureID 存储在一个实例变量中,创建一个新线程,最终调用我的 callback() 函数在同一个 ImageLoader 类中。 callback() 然后使用这个 pictureID 作为缓存图片的键。

问题

你看到泡菜了吗?如果我连续两次调用 getPicture( somePictureID ),而第一次调用的 callback() 函数还没有发生,我将覆盖之前的 callback() 函数将使用的 pictureID。 (如果您仍然没有看到泡菜,请参阅下面的代码。)

现在我知道您在想,为什么我不在变量上添加一点同步以使其成为线程安全的呢?

因为谁知道查询图片的线程要花多长时间,这真的会减慢加载多张图片的整个过程。

我是如何考虑解决它的

所以我的好主意是创建一个内部类,作为从属服务器并且只有一次使用。我在这个从属类中执行了一些函数一次,我从不重用该对象。

问题

这是解决此类问题的合适方法吗?我觉得这可能会陷入某种我不知道的模式。如果我对这个完全不满意,你能建议另一种解决方案吗?

简化代码

//the instance variable with a race condition
private int pictureID

//loads the image associated with the pictureID
public void getPicture( int pictureID )
{
Bitmap bitmap = cache.get( pictureID );
if ( bitmap != null )
{
//load image
return;
}

int post_params[] = { pictureID, /* more parameters */ };

this.pictureID = pictureID; //PROBLEM: race condition!
new HttpRequest( this ).execute( post_params ); //starts new thread and queries server
}

//gets called when the query finishes, json contains my image
public void callback( JSONObject json )
{
Bitmap bitmap = getBitmap( json ); //made up method to simplify code
cache.put( this.pictureID, bitmap ); //PROBLEM: race condition!

//load image
}

最佳答案

对我来说,这看起来像是 Memoizer 的经典案例模式,最简单的使用方法可能是 Guava 的 CacheBuilder ,类似于:

private LoadingCache<Integer, Image> cache = CacheBuilder.newBuilder().
build(new CacheLoader<Integer, Image>() {
@Override
public Image load(Integer key) throws Exception {
return httpGetImageExpensively(key);
}
});

public Image getPicture(int pictureId) {
return cache.getUnchecked(pictureId); // blocks until image is in cache
}

现在,HTTP 请求将发生在第一个为给定 ID 调用 getPicture() 的线程中;具有该 ID 的后续调用者将阻塞,直到第一个线程将图像放入缓存中,但您可以为不同的 ID 发出多个并发请求。

需要考虑的事情:

  • 加载速度有多慢?您需要超时机制吗?
  • 加载失败怎么办? cache.get() 方法抛出一个(已检查的)ExecutionException,这就是我使用 getUnchecked() 的原因,但这只是而是抛出一个(未检查的)UncheckedExecutionException。如果可能的话,我会在 httpGetImageExpensively() 中完成大部分错误处理,并仔细考虑可能出现的情况(ID 错误、DNS 故障等),但 getPicture() 的调用者 仍然需要以某种方式处理它。
  • 如果加载给定 ID 失败一次,是否每次都会失败?如果是这样,您可能不想每次都浪费时间重新 HTTP-GET ,并且您需要为此添加一种机制。请注意,是否值得重试的问题对于不同类型的失败可能有不同的答案。
  • 此实现会阻塞每个调用线程,直到有图像准备就绪。这对这个应用程序可行吗?如果没有,您可能希望将 getPicture() 替换为采用图像处理程序回调对象或 lambda 的更高级的东西,然后在内部将实际调用放入 httpGetImageExpensively()ExecutorService 上,因此 getPicture() 可以立即返回。 (根据应用程序,可能存在其他问题,例如,在 Swing 应用程序中,可能需要在事件分派(dispatch)线程上调用回调。)

关于java - 设计 : Object with single use?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28681855/

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