线程池执行器 - 1

“普通程序员迟早会意识到他们有许多小任务需要不时执行。”

“如果你正在编写游戏,那么它就是各个角色执行的动作。”

“如果你正在编写一个网络服务器,那么它就是来自用户的不同命令:上传照片、将其转码为所需格式、应用所需模板等。”

“迟早,所有大任务都会分解成一组小的、可管理的任务。”

“因此,在这种情况下,一个微妙的问题出现了:你应该如何管理它们?如果你需要在一分钟内执行数百个任务怎么办?为每个任务创建一个线程没有多大意义。Java 机器为每个线程分配相当多的资源。”

“换句话说,创建和销毁线程可能比任务本身花费更多的时间和资源。”

“Java 的创造者想出了一个优雅的解决方案来解决这个问题:ThreadPoolExecutor

ThreadPoolExecutor是一个包含两个东西的类:”

A) 一个任务队列,您可以在程序中出现任务时将其添加到其中。

B)一个线程池,它是一组执行这些任务的线程。

“更重要的是,一旦任务完成,线程就不会被销毁。相反,它们会进入休眠状态,以便在新任务出现时立即准备开始。”

“创建ThreadPoolExecutor时,您可以设置要创建的最大线程数和可以排队的最大任务数。换句话说,您可以将线程数限制为 10,例如,排队任务到 100。”

“这就是ThreadPoolExecutor 的工作原理:”

1) 当你添加一个新任务时,它被放在队列的末尾。

2) 如果队列已满,则抛出异常。

3) 完成一个任务后,每个线程从队列中取出下一个任务并开始执行它。

4)如果队列中没有任务,则线程进入休眠状态,直到有新任务加入。

“我们限制工作线程数量的方法的优势在于,我们拥有的线程越多,它们之间的干扰就越大。拥有 5-10 个工作线程和一长串任务比为大量任务创建 100 个线程,这些线程将相互竞争资源:内存、处理器时间、数据库访问等。”

“这是ThreadPoolExecutor的一个例子:”

例子
ExecutorService service = Executors.newFixedThreadPool(2);

for(int i = 0; i < 10; i++)
{
 service.submit(new Runnable() {
    public void run()
    {
     // Here we download something big from the Internet.
    }
 });
}

“呃,我没看到……”

“调用 newFixedThreadPool 方法时会创建一个ThreadPoolExecutor对象。”

因此,它非常易于使用。一旦您使用 submit 方法向它添加任务,它就会:

A) 唤醒休眠线程(如果有的话)来执行任务。

B) 如果没有等待线程,则它会为该任务创建一个新线程。

C) 如果达到最大线程数,则它只是将任务放在队列的末尾。

“我特意在示例中加入了 «这里我们从互联网上下载了一些大东西»。如果我们有 100 个任务 «从互联网上下载一些大东西»,那么同时运行很多它们就没有意义了——我们”将受到我们 Internet 连接的带宽限制的阻碍。在这种情况下,几个线程应该足够了。这就是您在上面的示例中看到的:”

ExecutorService service = Executors.newFixedThreadPool(2);

“事实证明,处理一堆任务并没有那么困难。”

“是的。比你想象的更容易。但金会告诉你的。”