- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我目前使用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/
我在我的应用程序中使用 Windows ThreadPools,每次调用 CreateThreadPoolWork() 时都会遇到 136 字节的内存泄漏,如通过 UMDH 所见: + 1257728
摘自对我之前一个问题的回答( Task.Factory.StartNew starts with a great delay despite having available threads in t
这有什么区别?请引用选项1和选项2。因为我遇到了麻烦,因为它们好像是一样的。它们运行正确 Thread ThreadPoolExecutor executor = (ThreadPoolExecuto
Windows Phone 8 SDK 文档没有描述 Windows.System.Threading.ThreadPool 之间的区别。和 System.Threading.ThreadPool .
我无法通过JSP使用Elasticsearch Java API。在下面,我试图解释我所做的事情。 :| 我已经按照 flex 指令在系统上安装了elasticseach 2.3.3,并在命令提示符下
我试图在 Thread 的帮助下找出控制台应用程序中运行的线程数: new Thread(() => { while (true) {
我们对来自 Android 应用程序的所有网络流量使用 Retrofit/OkHttp3。到目前为止,一切似乎都很顺利。 但是,我们现在偶尔会遇到我们的应用程序/进程用完文件句柄的情况。 Androi
我们应该为长时间运行的线程使用线程池还是启动我们自己的线程?有什么设计模式吗? 最佳答案 不幸的是,这取决于。没有硬性规定说您应该始终使用线程池。 线程池提供两个主要功能: 线程的委托(delegat
我只是实现了一个线程池,如这里所述 Allen Bauer on thread pools 非常简单的实现,可以正常工作,但是我的应用程序不再关闭。似乎有两个工作线程(和另一个线程,我想是排队线程)卡
我有以下代码: static void Main(string[] args) { Console.Write("Press ENTER to start..."); Console.
我在下面编写了一个示例程序。 class Program { static int x = 2; static void Main(string[] args)
我试图了解Parralel.For和ThreadPool.QueueUserWorkItem之间的区别。 硬件和软件: 英特尔i5(四核) Windows 7 64位教授 DotNet 4.5 案例1
当用户单击按钮时,我使用ThreadPool.QueueUserWorkItem生成了一个启动长时间运行的线程的线程。我想在线程完成时使按钮可见,以便用户可以单击它。 ThreadPool中是否有已完
我想要一个类似的功能: public static V callAsyncAndWait(Func func) { ThreadPool.QueueUserWorkItem(obj =>
我正在尝试编写一个 Java 多线程程序,对作为文件给出的 2 个矩阵执行乘法,并使用有限的线程总数。 例如,如果我将线程数设置为 16,我希望我的线程池能够重用这 16 个线程,直到所有任务完成。
我有一个 C# 控制台应用程序,其中有一个线程池。在线程池中会有一个类执行一个连续的方法(直到它运行了一段时间或者知道什么时候停止)。该方法连接到 HttpWebResponse 流并继续读取它。 问
我正在使用 Reflector 仔细阅读 .Net ThreadPool 的一些源代码,当它显示以下内容时: private static bool QueueUserWorkItemHelper(W
每当用户扫描条形码时,我都会触发一个线程。 大多数时候它是一个相当短的运行线程。但有时可能需要很长时间(等待调用 GUI 线程)。 我读到过,为此使用 ThreadPool 可能是个好主意,而不是为每
我有一个场景,我试图通过在可能的情况下在用户实际需要之前预取结果的一些子元素来转变为响应速度更快的 UI。我不清楚如何最好地处理线程,所以我希望有人可以提供一些建议。 场景 有一个搜索表单(.NET
我需要对事件进行排队并并行执行它们。 我的 C# 代码在阻塞集合中对事件进行排队,并使用 ThreadPool 在工作线程上执行每个事件。但是,如果事件以 2000 事件/秒或更高的速率排队,则会错过
我是一名优秀的程序员,十分优秀!