gpt4 book ai didi

java - ThreadPool 中任务的自定义顺序

转载 作者:太空狗 更新时间:2023-10-29 12:53:44 25 4
gpt4 key购买 nike

我目前使用FixedThreadPool 从网络上下载图片,如下所示:

ExecutorService mThreadPool = Executors.newFixedThreadPool(MAX_THREADS);

然后我只提交带有图像 URL 的新 Runnable,它要么从 URL 下载图像,要么如果它存在于缓存中加载它从那里开始。

我希望能够确保一次只有一个线程可以处理特定的 URL(以防止图片下载 MAX_THREADS 次的情况),并且如果该线程线程完成并下载我想要允许下一个(或所有,具有相同 URL)运行的图像,以从我的缓存中加载以前下载的图像。

这是我在简单(我希望如此)方案中显示的意思:http://i43.tinypic.com/xnz3f9.jpg

我看过一些使用 Queue 任务自定义实现 Runnable 的示例,但所有这些都需要我在执行这些任务之前知道所有 URL,我想在具有动态加载内容的 ListView 中使用它,这样该选项就不可能了。

感谢您的帮助。 :)

最佳答案

您将不得不实现某种同步方案(锁定)以防止第二个线程开始下载另一个线程已经在下载的同一文件。

想到的一个解决方案是传递您的每个 Runnable s 构造函数对 Map<String,Lock> 的引用和一个 ReentrantLock用于同步访问它。在与另一个文件一起下载时,将文件名作为键放在 map 中 ReentrantLock因为其他线程将作为值等待。

您锁定并检查 Map在下载文件之前。

如果那里没有条目,则创建一个新的 ReentrantLock并插入 Map .然后您解锁 Map 的锁本身。下载完文件后,您将再次锁定 map ,从 Map 中移除锁定。并解锁,然后解锁 map 。

如果那里有一个条目,您就知道另一个线程正在下载该文件并且您有一个锁可以使用。解锁 map ,锁定文件锁,等待获得锁。当您获得锁时,您就知道另一个线程已完成。

例子:

...
mapLock.lock();
Lock fileLock = fileMap.get(fileName);
if (fileLock == null)
{
fileLock = new ReentrantLock();
fileLock.lock();
fileMap.put(fileName, fileLock);
mapLock.unlock();

// download and deal with file

mapLock.lock();
fileMap.remove(fileName);
fileLock.unlock();
map.unlock();
}
else // someone is downloading this file!
{
mapLock.unlock();
fileLock.lock();
fileLock.unlock();

// When you get here, you know the other thread has downloaded the file
// do whatever it is you need to do in that case
}

更优雅的解决方案是使用 Condition连同 ReentrantLock (为了简洁起见,我不包括 setter/getter )

public class LockSet {
public Lock lock;
public Condition condition;

public LockSet() {
lock = new ReentrantLock();
condition = lock.newCondition();
}
}

现在有了这个方便的类,您可以执行以下操作:

mapLock.lock();
LockSet lockSet = fileMap.get(fileName);
if (lockSet == null)
{
lockSet = new LockSet();
fileMap.put(fileName, lockSet);
mapLock.unlock();

// download and deal with file

mapLock.lock();
fileMap.remove(fileName);
lockSet.lock.lock();
lockSet.condition.signalAll();
mapLock.unlock();
}
else // someone is downloading
{
lockSet.lock.lock();
mapLock.unlock();
lockSet.condition.await();

// once we get here, the file has finished downloading in the other thread
}

编辑:一个被作者删除的答案让我开始思考这个问题。

此方案的一个缺点是池中的线程偶尔会等待。由于您使用的是固定池大小,因此如果您同时对同一文件有多个请求,这可能会导致瓶颈情况。如果您要像您在帖子中提到的那样为任务实现排队机制,您实际上可以只使用 Map 就可以了。本身 ( Map<String,String> ) 没有双重锁定机制。

您的工作线程会将文件信息从队列中拉出,检查 map 以查看它是否存在(仍然锁定/解锁 map 锁),但在其他人正在下载文件的情况下将文件放回队列中(仅表明 Map 中存在该文件的条目 - 您可以只使用 null 作为值)

关于java - ThreadPool 中任务的自定义顺序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9150118/

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