使用线程池优化Echo模型

  在上一篇文章中 http://www.cnblogs.com/gosaint/p/8492356.html         我阐述了使用线程为每一个客户端创建一个工作线程来负责任务的执行。但是会存在如下的问题

  1.   服务器创建线程开销很大,有可能服务器创建线程消耗资源要比单独的和客户端通信所消耗的资源要大
  2.   如果存在大量的线程要同时创建,那么存在的内存开销很大。可能导致服务器系统内存不够
  3. 线程之间的切换消耗了大量的资源

  创建线程池可以较少线程的创建和销毁的开销,并且根据实际情况动态的调整线程池的大小。

  (1) 自定以线程池,让它继承ThreadGroup类

如下代码是自定义线程池代码的实现

package com.asiaInfo.caozg.ch_03.threadPool;

import java.util.LinkedList;

/**
 * @Authgor: gosaint
 * @Description:
 * @Date Created in 15:39 2018/3/2
 * @Modified By:自定义线程池的实现
 */
public class ThreadPool extends ThreadGroup {

    private boolean isClosed = false;//线程池是否关闭
    private LinkedList<Runnable> workQuee;//表示工作队列
    private static int threadPoolID;//表示线程池ID
    private int workThreadID;//表示工作线程池ID

    public ThreadPool(int poolSize) {
        //poolSize表示线程池中工作线程的数目
        //每一次的初始化,线程池ID都会自动增加
        super("ThreadPool-" + (threadPoolID++));
        //设置为守护线程
        setDaemon(true);
        workQuee = new LinkedList<>();//创建工作队列
        for (int i = 0; i < poolSize; i++) {
            new WorkThread().start();
        }
    }

    /**
     * 向工作队列中添加一个新的任务,让工作线程去执行
     *
     * @param task
     */
    public synchronized void execute(Runnable task) {
        if (isClosed) {
            //线程池关闭,则抛出如下的异常
            throw new IllegalStateException();
        }
        if (task != null) {
            workQuee.add(task);
            notify();//唤醒正在等待获取任务的工作线程getTask();
        }
    }

    /**
     * 从工作队列中取出一个线程,让线程执行任务
     *
     * @return
     * @throws InterruptedException
     */
    public synchronized Runnable getTask() throws InterruptedException {
        while (workQuee.size() == 0) {
            //当工作队列中的线程为0时,如果线程池关闭,则返回null.负责,等待任务
            if (isClosed) {
                return null;
            } else {
                wait();
            }
        }
        return workQuee.removeFirst();//从工作队列中弹出第一个元素
    }

    /**
     * 关闭线程池
     */
    public synchronized void closed() {
        //线程池没有关闭
        if (!isClosed) {
            isClosed = true;
            workQuee.clear();//清除工作队列
            interrupt();//中断所有的线程
        }
    }

    /**
     * 等在工作线程将若有的任务执行完毕
     */
    public void join() {
        synchronized (this) {
            isClosed = true;
            notifyAll();//唤醒所有的等待任务的工作线程
        }
        //activeCount() 返回此线程组中活动线程的估计数。 来自ThreadGroup
        Thread[] threads = new Thread[activeCount()];
        // enumerate[list] 把此线程组及其子组中的所有活动线程复制到指定数组中。
        int count = enumerate(threads);//返回所有的活着的线程数量
        for (int i = 0; i < count; i++) {
            try {
                threads[i].join();//等待所有的活动的工作宣称的结束
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 内部类,创建的工作线程对象
     */
    private class WorkThread extends Thread {
        public WorkThread() {
            super(ThreadPool.this, "WorkThread-" + workThreadID++);
        }

        @Override public void run() {
            //线程没有中断
            while (!isInterrupted()) {
                Runnable task = null;
                try {
                    task = getTask();//获取任务
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (task == null) {
                    return;
                }
                try {
                    task.run();//运行任务
                } catch (Throwable t) {
                    t.printStackTrace();
                }

            }
        }
    }
}

1 流程执行的分析:

关注两个成员变量:

  1> isClosed---->表示线程池是否关闭;workQuee:表示的工作队列,使用的类型是LinkedList.

  2> 在构造器中初始化工作队列,然后启动每一个线程;

  3>execute()方法的执行如下所示:线程池对象的核心就是将线程添加到工作队列中

  4>getTask()方法 从工作队列中获取线程

  5> closed()方法:关闭线程池

  6>join()方法;等待线程执行完所有的任务

2 测试自定义线程池:

package com.asiaInfo.caozg.ch_03.threadPool;

import static java.lang.Integer.parseInt;

/**
 * @Authgor: gosaint
 * @Description:
 * @Date Created in 16:25 2018/3/2
 * @Modified By:线程池测试
 */
public class ThreadPoolTester {

    public static void main(String[] args) {
        if (args.length != 2) {
            System.out.println(
                    "用法: java ThreadPoolTest numTasks poolSize");
            System.out.println(
                    "  numTasks - integer: 任务的数目");
            System.out.println(
                    "  numThreads - integer: 线程池中的线程数目");
            return;
        }
        int numTasks = Integer.parseInt(args[0]);
        int poolSize = Integer.parseInt(args[1]);

        ThreadPool threadPool = new ThreadPool(poolSize);  //创建线程池

        // 运行任务
        for (int i = 0; i < numTasks; i++)
            threadPool.execute(createTask(i));

        threadPool.join();  //等待工作线程完成所有的任务
        // threadPool.close(); //关闭线程池
    }//#main()

    /**
     * 定义了一个简单的任务(打印ID)
     */
    private static Runnable createTask(final int taskID) {
        return new Runnable() {
            public void run() {
                System.out.println("Task " + taskID + ": start");
                try {
                    Thread.sleep(500);  //增加执行一个任务的时间
                } catch (InterruptedException ex) {
                }
                System.out.println("Task " + taskID + ": end");
            }
        };
    }
}

设置参数5,3.表示5个任务3个线程去执行:

原文地址:https://www.cnblogs.com/gosaint/p/8494423.html

时间: 2024-10-15 09:22:54

使用线程池优化Echo模型的相关文章

Mysql线程池优化笔记

Mysql线程池优化我是总结了一个站长的3篇文章了,这里我整理到一起来本文章就分为三个优化段了,下面一起来看看. Mysql线程池系列一(Thread pool FAQ) 首先介绍什么是mysql thread pool,干什么用的?使用线程池主要可以达到以下两个目的:1.在大并发的时候,性能不会因为过载而迅速下降.2.减少性能抖动 thread pool的工作原理?线程池使用分而治之的方法来限制和平衡并发性.与默认的thread_handling不同,线程池将连接和线程划分开,所以连接数量和执

java笔记--使用线程池优化多线程编程

使用线程池优化多线程编程 认识线程池 在Java中,所有的对象都是需要通过new操作符来创建的,如果创建大量短生命周期的对象,将会使得整个程序的性能非常的低下.这种时候就需要用到了池的技术,比如数据库连接池,线程池等. 在java1.5之后,java自带了线程池,在util包下新增了concurrent包,这个包主要作用就是介绍java线程和线程池如何使用的. 在包java.util.concurrent下的 Executors类中定义了Executor.ExecutorService.Sche

使用线程池优化多线程编程

Java中的对象是使用new操作符创建的,如果创建大量短生命周期的对象,这种方式性能非常低下.为了解决这个问题,而发明了池技术. 对于数据库连接有连接池,对于线程则有线程池. 本实例介绍两种方式创建1000个短生命周期的线程,第一种是普通方式,第二种是线程池的方式.通过时间和内存消耗的对比,就可以很明显地看出线程池的优势. 实例结果如下: 说明:使用线程池创建对象的时间是15毫秒,说明线程池是非常高效的. 关键技术: Executors类为java.util.concurrent包中所定义的Ex

使用自定义线程池优化EchoServer

在上一篇文章中http://www.cnblogs.com/gosaint/p/8494423.html 我自定义了线程池ThreadPool.现在在我的EchoServer中使用自定义线程池去负责和客户端的通讯,代码如下所示: package com.asiaInfo.caozg.ch_03.threadPool; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; imp

python GIL锁 锁 线程池 生产者消费模型

python的GIL 锁 python内置的一个全局解释器锁 , 锁的作用就是保证同一时刻一个进程中只有一个线程可以被cpu调度 为什么有这把GIL锁? python语言的创始人在开发这门语言时 , 目的快速把语言开发出来 , 如果加上GIL锁(C语言加锁) , 切换时按照100条字节指令来进行线程间的切换 锁 : 1.锁 : Lock(1次放1个) 线程安全 , 多线程操作时 , 内部会让所有线程排队处理 , 如 : list / dict / Queue 线程不安全 + 人  =>排队处理

稳定性 耗时 监控原因分析-- dubbo rpc 框架 的线程池,io 连接模型. 客户端,服务端

上次 提到的Nagle算法特性有可能是dubbo调用”网络耗时高“的始作俑者,后来又仔细看了下dubbo的代码,发现dubbo在consumer端已经将tcp设置成非延迟(即关闭Nagle特性)了,代码片段如下: order模块中调用量最高的接口是查询未完成订单,调用量达到每10秒18000,如下: 但该接口在order这边的平均耗时特别低(尖刺是由发布引起的,这里忽略),才1毫秒: 该接口直接由kop来调用,我们看kop这边的平均耗时: 可以看出,在低峰期,kop这边的耗时和order的耗时是

线程池与非线程池应用场景及模型对比分析

在网络编程中经常用到线程池和连接池,今天就对其中常用的线程池的基本应用场景和模型做个简单的对比分析. 1.  业务流程对比 a.  非线程池业务流模型: 上图标识了基本的非线程池的线程模型,前端1有多少连接则前端客户端2与前端服务器端3均需建立一对一的线程数进行响应的连接.前端服务器端3与后端服务器端4也需建立响应数目的线程进行连接处理相关业务. 当一个任务处理完毕后线程退出,在下一个任务到来的时候前端服务器端创建新的线程来处理新的任务. b.线程池模型: 上图标识了基本的线程池模型.前端客户端

MySQL详解(7)-----------MySQL线程池总结(一)

线程池是Mysql5.6的一个核心功能,对于服务器应用而言,无论是web应用服务还是DB服务,高并发请求始终是一个绕不开的话题.当有大量请求并发访问时,一定伴随着资源的不断创建和释放,导致资源利用率低,降低了服务质量.线程池是一种通用的技术,通过预先创建一定数量的线程,当有请求达到时,线程池分配一个线程提供服务,请求结束后,该线程又去服务其他请求. 通过这种方式,避免了线程和内存对象的频繁创建和释放,降低了服务端的并发度,减少了上下文切换和资源的竞争,提高资源利用效率.所有服务的线程池本质都是位

线程池 API (转)

文档原始地址 目录 线程池概述 线程池对象 回调环境对象 工作对象 等待对象 计时器对象 I/O 完成对象 使用清理组简化清理 回调实例 API 随着 Windows Vista® 的发布和 Windows Server® 2008 的即将问世,Microsoft 为托管应用程序的开发人员提供了改进的 Windows® 平台,它包含多种新技术,使得令原本 Windows 开发人员从中受益的改进能被广为利用.例如,自从 Windows 2000 发布以来,已是该平台组成部分的线程池组件经历了一次完