Java简单实现线程池

本文实例为大家分享了Java简单实现线程池的具体代码,供大家参考,具体内容如下

一、线程池

线程池是一种缓冲提高效率的技术。
相当于一个池子,里面存放大量已经创建好的线程,当有一个任务需要处理时, 可以直接从池子里面取一个线程去执行它。 包括内存池,很多缓冲的技术都是采用这种技术。 其实理解起来很简答!

为什么需要线程池,这种池的技术?

1.1 减少开辟资源和销毁资源带来的损耗。

开辟线程,申请内存(具体的可以看C语言中malloc底层实现原理),销毁线程、释放内存资源等一些操作都是有时间消耗的。
因此一开始开辟大量的资源进行管理,需要使用时从池中取一个去使用, 使用完毕后再放回池中管理, 这样可以避免资源开辟和销毁带来的时间损耗。

1.2 提高响应。

用户来了一个请求, 能够立刻从开辟好的线程池中取一个线程去处理执行。 提高响应效率,提高用户体验。

1.3 有效管理资源

管理资源统一开辟和销毁, 监控线程状态和调优

二、线程池分析

对于线程池的实现我们划分为2个部分

1、线程安全的任务队列(采用队列,不过是线程安全的而已),保证工作线程在去任务时不会发生冲突(重复取同一个任务处理,二次执行或者多次的问题)。
2、对工作线程的监管(采用是List管理工作线程),方便线程的销毁和管理。

线程池处理逻辑:

1、每当添加一个任务,就会从线程池中取一个工作线程去处理执行它。
2、没有任务处理时, 工作线程应该处于阻塞状态等待任务到来, 不会竞争占用CPU资源
3、线程池相当于生产-消费模型, 只不过生产线程的中生产任务不同罢了。

3、主线程相当于监管线程,最终负责工作线程的销毁。

三、线程池实现

1、 工作线程Worker

1.1、工作线程负责从阻塞任务队列中取出任务执行。由于存在很多个线程对同一个队列操作,因此这个任务队列一定得是线程安全的(采用BlockingQueue接口, 这是GUC提供的,线程安全)
1.2、工作线程的创建方式属于线程创建的方式之一。
1.3、每个工作线程都维护一个阻塞任务队列。
1.4、线程的执行方法run()中,以线程的中断状态为循环判断条件(方便线程销毁, 只要将工作线程的中断状态置为true即可释放工作线程)其次就是BlockingQueue接口提供的take()方法。

该方法在队列没有元素时处于阻塞状态,直接取到元素,这样就解决了没有任务工作线程处于阻塞状态,不会抢占CPU

//实现工作线程 - 工作线程中维护了公有的任务队列(阻塞), 工作线程的执行逻辑。 循环取队列中的任务去执行处理。
class Worker extends Thread {
    //阻塞任务队列 - 可以保证多个线程对队列操作, 线程安全
    private BlockingQueue<Runnable> queue = null;
    //每个工作线程都会有一个阻塞队列,这个队列中保存了所有的任务
    public Worker(BlockingQueue<Runnable> queue, int id) {
        this.queue = queue;
     //   Thread.currentThread().setName("郝梦武" + id + "号工作线程");
    }

    //工作线程执行内容
    @Override
    public void run() {
        //每个线程通过isInterrupted()判断线程异常状态。
        try {
            while (!Thread.currentThread().isInterrupted()) {
                //如果线程正常, 返回false, 出现异常, 返回true, 该状态默认为false
                Runnable command = queue.take();    //如果队列为空, take会让线程阻塞
                System.out.println(Thread.currentThread().getName() + "正在处理任务" + command.hashCode());
                command.run();
            }
        }
        catch(InterruptedException e) {
            System.out.println(Thread.currentThread().getName() + "被中止了");
        //    e.printStackTrace();      //不需要抛出异常
        }
    }
}

2、线程池对象MyThreadPool

1、创建工作线程并管理,添加任务。
2、销毁所有工作线程

//线程池 - 维护很多个线程, 当来一个任务时, 从线程池中获取一个线程去处理执行。
//好处: 防止线程频繁开辟和销毁带来的性能损耗
class MyThreadPool {
    //创建任务线程安全的队列, 保证多个线程对这个队列操作时是线程安全的
    private BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>();
    //线程管理列表 - 这个列表保存了所有线程对象的引用, 方便后续的管理
    private List<Worker> Wokers = new ArrayList<>();
    private final static int maxWorkerCount = 10;   //线程池最大允许的个数

    //execute方法
    public void execute(Runnable command) throws InterruptedException {
        if(Wokers.size() < maxWorkerCount) {
            //创建一个新的工作线程
            Worker worker = new Worker(queue, Wokers.size());   //创建工作线程
            worker.start();                      //创建的工程线程启动
            Wokers.add(worker);                  //添加到管理列表中
        }
        queue.put(command);                      //添加任务到线程安全的队列中
    }

    //销毁所有线程 - 将每个线程中状态置为中断状态方法, 并且
    public void shutDown() throws InterruptedException {
        for(Worker worker : Wokers) {
            worker.interrupt();                  //将线程的状态置为中断, 调用isInterruptd()返回值为true
        }
        //并且让主线程join阻塞等待所有工作线程
        for(Worker worker : Wokers) {
            worker.join();                       //join方法可以让调用的线程处于阻塞状态, 知道等待的线程结束完毕之后就会恢复
        }
        //执行到这块, 代表所有的线程销毁完毕
        System.out.println("所有工作线程销毁完毕!");
    }
}

3、测试代码

class MyRunnable implements Runnable {
    private int num;
    MyRunnable(int num) {
        this.num = num;
    }
    @Override
    public void run() {
        System.out.println("正在执行任务: " + num);
    }
}

public static void main(String[] args) throws InterruptedException {
     MyThreadPool myThreadPool = new MyThreadPool();
     for(int i = 0; i < 1000; i++) {
         myThreadPool.execute(new MyRunnable(i + 1));
     }
     Thread.sleep(2000);   //主线程休眠2s
     myThreadPool.shutDown();  //销毁所有工作线程
     System.out.println("线程池已经被销毁了");
     }

4、测试结果

总结:

以上的代码只是简单模拟实现了线程池。
不仅仅是线程池,内容池,还有很多池的应用场景。
池的技术虽然能够起到快速响应的特点,但是还是存在问题。
第一点: 池需要在一开始创建很多资源, 这和我们机器内存大小有关系。
第二点: 池中的线程过多,但是任务过少,导致很多线程浪费掉, 因此池中开辟多大的资源需要根据实际情况而言。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Java线程池ThreadPoolExecutor原理及使用实例

    引导 要求:线程资源必须通过线程池提供,不允许在应用自行显式创建线程: 说明:使用线程池的好处是减少在创建和销毁线程上所花的时间以及系统资源的开销,解决资源不足的问题.如果不使用线程池,有可能造成系统创建大量同类线程而导致消耗内存或者"过度切换"的问题. 线程池介绍线程池概述   线程池,顾名思义是一个放着线程的池子,这个池子的线程主要是用来执行任务的.当用户提交任务时,线程池会创建线程去执行任务,若任务超过了核心线程数的时候,会在一个任务队列里进行排队等待,这个详细流程,我们会后面细

  • Java 使用线程池执行多个任务的示例

    在执行一系列带有IO操作(例如下载文件),且互不相关的异步任务时,采用多线程可以很极大的提高运行效率.线程池包含了一系列的线程,并且可以管理这些线程.例如:创建线程,销毁线程等.本文将介绍如何使用Java中的线程池执行任务. 1 任务类型 在使用线程池执行任务之前,我们弄清楚什么任务可以被线程池调用.按照任务是否有返回值可以将任务分为两种,分别是实现Runnable的任务类(无参数无返回值)和实现Callable接口的任务类(无参数有返回值).在打代码时根据需求选择对应的任务类型. 1.1 实现

  • Java利用线程工厂监控线程池的实现示例

    ThreadFactory 线程池中的线程从哪里来呢?就是ThreadFoctory public interface ThreadFactory { Thread newThread(Runnable r); } Threadfactory里面有个接口,当线程池中需要创建线程就会调用该方法,也可以自定义线程工厂 public class ThreadfactoryText { public static void main(String[] args) { Runnable runnable=

  • 深入理解Java线程池从设计思想到源码解读

    线程池:从设计思想到源码解析 前言初识线程池线程池优势线程池设计思路 深入线程池构造方法任务队列拒绝策略线程池状态初始化&容量调整&关闭 使用线程池ThreadPoolExecutorExecutors封装线程池 解读线程池execute()addWorker()Worker类runWorker()processWorkerExit() 前言 各位小伙伴儿,春节已经结束了,在此献上一篇肝了一个春节假期的迟来的拜年之作,希望读者朋友们都能有收获. 根据穆氏哲学,投入越多,收获越大.我作此文时

  • 浅谈Java线程池的7大核心参数

    前言 java中经常需要用到多线程来处理一些业务,我不建议单纯使用继承Thread或者实现Runnable接口的方式来创建线程,那样势必有创建及销毁线程耗费资源.线程上下文切换问题. 同时创建过多的线程也可能引发资源耗尽的风险,这个时候引入线程池比较合理,方便线程任务的管理. java中涉及到线程池的相关类均在jdk1.5开始的java.util.concurrent包中,涉及到的几个核心类及接口包括: Executor.Executors.ExecutorService.ThreadPoolE

  • Java多线程之线程池七个参数详解

    ThreadPoolExecutor是JDK中的线程池实现,这个类实现了一个线程池需要的各个方法,它提供了任务提交.线程管理.监控等方法. 下面是ThreadPoolExecutor类的构造方法源码,其他创建线程池的方法最终都会导向这个构造方法,共有7个参数:corePoolSize.maximumPoolSize.keepAliveTime.unit.workQueue.threadFactory.handler. public ThreadPoolExecutor(int corePoolS

  • java 定时器线程池(ScheduledThreadPoolExecutor)的实现

    前言 定时器线程池提供了定时执行任务的能力,即可以延迟执行,可以周期性执行.但定时器线程池也还是线程池,最底层实现还是ThreadPoolExecutor,可以参考我的另外一篇文章多线程–精通ThreadPoolExecutor. 特点说明 1.构造函数 public ScheduledThreadPoolExecutor(int corePoolSize) { // 对于其他几个参数在ThreadPoolExecutor中都已经详细分析过了,所以这里,将不再展开 // 这里我们可以看到调用基类

  • Java 自定义线程池和线程总数控制操作

    1 概述 池化是常见的思想,线程池是非常典型的池化的实现,<Java并发编程实战>也大篇幅去讲解了Java中的线程池.本文实现一个简单的线程池. 2 核心类 [1]接口定义 public interface IThreadPool<Job extends Runnable> { /** * 关闭线程池 */ public void shutAlldown(); /** * 执行任务 * * @param job 任务 */ public void execute(Job job);

  • java多线程CountDownLatch与线程池ThreadPoolExecutor/ExecutorService案例

    1.CountDownLatch: 一个同步工具类,它允许一个或多个线程一直等待,直到其他线程的操作执行完后再执行. 2.ThreadPoolExecutor/ExecutorService: 线程池,使用线程池可以复用线程,降低频繁创建线程造成的性能消耗,同时对线程的创建.启动.停止.销毁等操作更简便. 3.使用场景举例: 年末公司组织团建,要求每一位员工周六上午8点到公司门口集合,统一乘坐公司所租大巴前往目的地. 在这个案例中,公司作为主线程,员工作为子线程. 4.代码示例: package

  • 浅谈Java ThreadPoolExecutor的使用

    一.前言 线程池主要由以下4个核心组件组成. 线程池管理器:用于创建并管理线程池 工作线程:线程池中执行具体任务的线程 任务接口:用于定义工作线程的调度和执行策略,只有线程实现了该接口,线程中的任务才能被线程池调度 任务队列:放待处理的任务,新的任务将会不断被加入队列中,执行完成的任务将从队列中移除 二.ThreadPoolExecutor 如下是线程池的构造方法 public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, l

  • Java ThreadPoolExecutor 线程池的使用介绍

    Executors Executors 是一个Java中的工具类. 提供工厂方法来创建不同类型的线程池. 从上图中也可以看出, Executors的创建线程池的方法, 创建出来的线程池都实现了 ExecutorService接口. 常用方法有以下几个: newFixedThreadPool(int Threads): 创建固定数目线程的线程池, 超出的线程会在队列中等待. newCachedThreadPool(): 创建一个可缓存线程池, 如果线程池长度超过处理需要, 可灵活回收空闲线程(60

  • java线程池对象ThreadPoolExecutor的深入讲解

    使用线程池的好处 1.降低资源消耗 可以重复利用已创建的线程降低线程创建和销毁造成的消耗. 2.提高响应速度 当任务到达时,任务可以不需要等到线程创建就能立即执行. 3.提高线程的可管理性 线程是稀缺资源,如果无限制地创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一分配.调优和监控 ThreadPoolExecutor 介绍: java 提供的线程池类: ThreadPoolExecutor 作用: 两个作用: 1,用于分离执行任务和当前线程: 2,主要设计初衷:重复利用T

随机推荐