博客
关于我
手写线程池
阅读量:759 次
发布时间:2019-03-21

本文共 4677 字,大约阅读时间需要 15 分钟。

理解线程池以及实现一个简单的线程池

为什么需要线程池

我们不必一味向线程池看齐,但是理解其背后的原理有助于更好地利用资源。在没有线程池的情况下,系统会经常因为无限创建线程而崩溃。每个线程都需要资源支持,就像吃火锅时需要长凳一样,线程池类似于长凳,协调大量订单="/">线程池的工作机制

线程池的工作原理

核实海底捞的场景,这部分已经理解完毕。现在让我们转而讨论线程池的工作机制。实际上,线程池在底层是一个无差错的队列系统。每次新的请求到达时,通过 ticket 块塞队列方式下单,这些被称为 tasks 的工作单元会被分配给线程池中的工作线程。此处的关键是理解如何有效地管理这些请求。

在我们的一个简单的线程池中,队列被设置为我们步骤中提到的容量大小,而线程被启动成个数固定的池。

初始设置存储要执行的任务,块创建固定数量的线程,我们称它们为 worker

实现线程池的元素

如果你决心自己动手写一个线程池,你需要了解其中的这些关键部分。存储你的任务,使用-linked hash set或者其他的队列组件。这里我们使用iso Nutzungios e edek久 ,我们需要一个阻塞队列。选择一个队列实现是关键性的一步

接下来,我们需要管理员工的数量。每个员工就会成为一个 thread。他们需要一直保持运行状态,直到他们从队列获得任务进行处理。在glassDoor例子中,可以看到我们的worker 线程就拿着pool作为背景语境。

这部分讨论略大,分类整理网用,包括以下几个关键点:

  • 队列:用来存储需要执行的任务。我们可以采用阻塞队列。
  • 工作人员:采用池化的线程,这些线程便利地实现任务处理.
  • 线程间的协调和管理.

这是一个高效的线程池输入,采用 pool统一管理线程。

开始编码

在编写代码之前,让我们理清需求。我们的线程池需要处理什么样的任务序列?在我们的例子中,任务由一个Runnable实现。每次提交任务会被放置到队列中。线程池中的 worker 线程会在空闲时就从队列中获取任务并运行。

import java.util.ArrayList;import java.util.List;import java.util.concurrent.BlockingQueue;import java.util.concurrent.LinkedBlockingDeque;public class MyThreadPool {    // 队列容量,设置为阻塞队列形式    private final BlockingQueue
blockingQueue = new LinkedBlockingDeque<>(); // 存储工作线程,保持其处于就绪状态 private final List
workers = new ArrayList<>(); // 线程池的状态标志 private volatile boolean isRunning = true; public MyThreadPool(int taskQueueSize, int workerCount) { if (taskQueueSize <= 0 || workerCount <= 0) { throw new IllegalArgumentException("Task queue and worker count must be at least 1"); } // 初始化队列 this.blockingQueue = new LinkedBlockingDeque<>(taskQueueSize); // 初始化工作线程 this.workers = new ArrayList<>(); for (int i = 0; i < workerCount; i++) { Thread worker = new Thread() { @Override public void run() { Runnable task = null; try { while (isRunning || !blockingQueue.isEmpty()) { if (isRunning) { task = blockingQueue.take(); } else { task = blockingQueue.poll(); } } if (task != null) { task.run(); System.out.println("Worker thread: " + Thread.currentThread().getName() + " executed task"); } } catch (InterruptedException e) { e.printStackTrace(); } } }; worker.start(); this.workers.add(worker); } } // 提交要执行的任务 public boolean submit(Runnable task) { if (!isRunning) { return false; } if (blockingQueue.size() < this.blockingQueue.remainingCapacity()) { return this.blockingQueue.offer(task); } else { return false; } } // 关闭线程池 public void shutDown() { this.isRunning = false; for (Thread worker : workers) { if (worker.getState() == Thread.State.BLOCKED) { worker.interrupt(); } } }}

代码解释

1 noises// 队列设置最大的容量大小是 taskQueueSize,这样可以避免队列过载线程池的所有线程都是预先创建好的,保持在就绪状态,这样可以在遇到任务时立即分配处理。而非每次线程创建时就启动线程(A therapist的思路可能会引发线程数量激增的问题)

2 submit方法的作用就是将一个新的 runnable 任务加入队列中。针对非空余量的队列来说,才能成功提交任务。我们需要注意容量限制。

3 shutDown方法的动作是停止线程池继续运行,并对正在等待任务的外部工作人员发出中断信号。这是必要的操作,因为我们希望线程池能够干净地停止当前的处理过程,而不是等待堆积的任务无法完成。

测试与结果

让我们用代码测试一下线程池的性能与正确工作。

public class MyThreadPoolDemo {    public static void main(String[] args) {        MyThreadPool pool = new MyThreadPool(3,3);        for (int i = 0; i < 3; i++) {            pool.submit(new Runnable() {                @Override                public void run() {                    System.out.println("## Task #" + i);                }            });            try {                Thread.sleep(500);            } catch (InterruptedException e) {                e.printStackTrace();            }        }        pool.shutDown();    }}

分析测试结果

在这个测试中,我们定义了一个即使线程池的大小为3,那么最多同时执行三次。每个任务都会被提交到队列中。在提交后设置500毫秒的等待时间,这能观察到线程池的行为。

可以详细分析每一步的输出:

  • 第一个任务提交,打印“## Task #0”,此时线程池有一个任务在队列中
  • 第二个任务提交,打印“## Task #1”,两个任务在队列中
  • 第三个任务提交,打印“## Task #2”,三项任务全部在队列中
  • 然后,第五个百米,在每次提交的时候,我们会让线程进入睡眠状态。我们发现在这段时间内,如果线程已经存在了,它就不会被打断,直到线程池中的工作人员从队列里拿来任务进行处理。

    之后,在 pool.shutDown() 被调用,线程池中的所有工作人员都会被停止处理。现在的关键问题是,工作人员是正确地完成它们运袅并退出。

    通过运行这个程序,你们将注意到线程池中的每个工作线程只会处理到它被==-d或队列不再有任务时停止。而线程池的情况下,调用 shutDown() 后会使线程发散停止处理。

    这种方式确保了在线程池关闭后,任何使得工作线程处于等待状态的任务也能得到中断处理,从而线程安全地退出。

    总结

    在这段时间的学习中,我们理解了线程池的重要性,它如何解决了线程资源管理的难题。创建一个简单的线程池,能够给我们带来关于线程管理的直接练习。通过测试代码,我们看到线程池在操作中是那么高效和自然。线程池似乎在处理任务时远超过线性速度的预期,从而成为我们日常编程中必不可少的工具。

    转载地址:http://gxygz.baihongyu.com/

    你可能感兴趣的文章
    MySQL之CRUD
    查看>>
    MySQL之DML
    查看>>
    Mysql之IN 和 Exists 用法
    查看>>
    MYSQL之REPLACE INTO和INSERT … ON DUPLICATE KEY UPDATE用法
    查看>>
    MySQL之SQL语句优化步骤
    查看>>
    MYSQL之union和order by分析([Err] 1221 - Incorrect usage of UNION and ORDER BY)
    查看>>
    Mysql之主从复制
    查看>>