参考文章:

[1]创建线程池 http://sunnylocus.iteye.com/blog/223327?page=2#comments

[2]线程组ThreadGroup  http://hubingforever.blog.163.com/blog/static/1710405792010913191791/

一、为什么要用线程池:

1)减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务

2)可以根据系统的承受能力,调整线程池中工作线程的数目,防止因为消耗过多的内存,而把服务器累趴下(每个线程需要大约1MB内存,线程开的越多,消耗的内存也就越大,最后死机)

二、ThreadGroup类介绍

1.概括:

1)ThreadGroup线程组表示一个线程的集合。

2)此外,线程组也可以包含其他线程组。

3)线程组构成一棵树,在树中,除了初始线程组外,每个线程组都有一个父线程组。

4)允许线程访问有关自己的线程组的信息,但是不允许它访问有关其线程组的父线程组或其他任何线程组的信息。

2.在Java中每个线程都属于某个线程组(ThreadGroup)。

例如,如果在main()中产生一个线程,则这个线程属于main线程组(其名字为"main")管理的一员,您可以使用下面的指令来获得目前线程所属的线程组名称:

Thread.currentThread().getThreadGroup().getName();  

3.每一个线程产生时,都会被归入某个线程组,视线程是在哪个线程组中产生而定。如果没有指定,则归入产生该子线程的线程所在的线程组中。

您也可以自行指定线程组,线程一旦归入某个组,就无法更换组。

java.lang.ThreadGroup类正如其名,可以统一管理整个线程组中的线程,您可以使用以下方式来产生线程组,而且一并指定其线程组:

ThreadGroup threadGroup1 = newThreadGroup("group1");  

ThreadGroup threadGroup2 = newThreadGroup("group2");  

Thread thread1 =new Thread(threadGroup1,"group1's member");  

Thread thread2 =new Thread(threadGroup2,"group2's member");  

4.ThreadGroup中的某些方法,可以对所有的线程产生作用,例如interrupt()方法可以interrupt线程组中所有的线程,

setMaxPriority()方法可以设置线程组中线程所能拥有的最高优先权(本来就拥有更高优先权的线程不受影响)。

5.如果您想要一次获得线程组中所有的线程来进行某种操作,可以使用enumerate()方法,例如:

Thread[] threads = newThread[threadGroup1.activeCount()];  

threadGroup1.enumerate(threads); 

activeCount()方法获得线程组中正在运行的线程数量,enumerate()方法要传入一个Thread数组,

它将线程对象设置到每个数组字段中,然后就可以通过数组索引来操作这些线程。

6.ThreadGroup中有一个uncaughtException()方法。当线程组中某个线程发生Unchecked exception异常时,由执行环境调用此方法进行相关处理,如果有必要,您可以重新定义此方法。

7.构造方法

public ThreadGroup(String name)
    构造一个新线程组。新线程组的父线程组是目前正在运行线程的线程组。  不使用任何参数调用父线程组的 checkAccess 方法;这可能导致一个安全性异常。

参数:

name - 新线程组的名称。

抛出:

SecurityException - 如果当前线程不能在指定的线程组中创建线程。

public ThreadGroup(ThreadGroupparent,String name)

创建一个新线程组。新线程组的父线程组是指定的线程组。

不使用任何参数调用父线程组的 checkAccess 方法;这可能导致一个安全性异常。

参数:

parent - 父线程组。

name - 新线程组的名称。

抛出:

NullPointerException - 如果线程组参数为 null。

SecurityException - 如果当前线程不能在指定的线程组中创建线程。

三、线程池类模拟代码:

package com.tdt.impl.ls;    

import java.util.LinkedList;    

/**
* @project LocationGateway
* @author sunnylocus
* @verson 1.0.0
* @date Aug 2, 2008
* @jdk 1.4.2
*/
public class ThreadPool extends ThreadGroup {
private boolean isClosed = false; //线程池是否关闭
private LinkedList workQueue; //工作队列
private static int threadPoolID = 1; //线程池的id
public ThreadPool(int poolSize) { //poolSize 表示线程池中的工作线程的数量 super(threadPoolID + ""); //指定ThreadGroup的名称
setDaemon(true); //继承到的方法,设置是否守护线程池
workQueue = new LinkedList(); //创建工作队列
for(int i = 0; i < poolSize; i++) {
new WorkThread(i).start(); //创建并启动工作线程,线程池数量是多少就创建多少个工作线程
}
} /** 向工作队列中加入一个新任务,由工作线程去执行该任务*/
public synchronized void execute(Runnable task) {
if(isClosed) {
throw new IllegalStateException();
}
if(task != null) {
workQueue.add(task);//向队列中加入一个任务
notify(); //唤醒一个正在getTask()方法中待任务的工作线程
}
} /** 从工作队列中取出一个任务,工作线程会调用此方法*/
private synchronized Runnable getTask(int threadid) throws InterruptedException {
while(workQueue.size() == 0) {
if(isClosed) return null;
System.out.println("工作线程"+threadid+"等待任务...");
wait(); //如果工作队列中没有任务,就等待任务
}
System.out.println("工作线程"+threadid+"开始执行任务...");
return (Runnable) workQueue.removeFirst(); //反回队列中第一个元素,并从队列中删除
} /** 关闭线程池 */
public synchronized void closePool() {
if(! isClosed) {
waitFinish(); //等待工作线程执行完毕
isClosed = true;
workQueue.clear(); //清空工作队列
interrupt(); //中断线程池中的所有的工作线程,此方法继承自ThreadGroup类
}
} /** 等待工作线程把所有任务执行完毕*/
public void waitFinish() {
synchronized (this) {
isClosed = true;
notifyAll(); //唤醒所有还在getTask()方法中等待任务的工作线程
}
Thread[] threads = new Thread[activeCount()];
int count = enumerate(threads);
for(int i =0; i < count; i++) { //等待所有工作线程结束
try {
threads[i].join(); //等待工作线程结束
}catch(InterruptedException ex) {
ex.printStackTrace();
}
}
} /**
* 内部类,工作线程,负责从工作队列中取出任务,并执行
* @author sunnylocus
*/
private class WorkThread extends Thread {
private int id;
public WorkThread(int id) {
//父类构造方法,将线程加入到当前ThreadPool线程组中
super(ThreadPool.this,id+"");
this.id =id;
}
public void run() {
while(! isInterrupted()) { //isInterrupted()方法继承自Thread类,判断线程是否被中断
Runnable task = null;
try {
task = getTask(id); //取出任务
}catch(InterruptedException ex) {
ex.printStackTrace();
}
//如果getTask()返回null或者线程执行getTask()时被中断,则结束此线程
if(task == null) return; try {
task.run(); //运行任务
}catch(Throwable t) {
t.printStackTrace();
}
}// end while
}// end run
}// end workThread
}

使用ThreadGroup模拟线程池的更多相关文章

  1. wait/notify模拟线程池

    线程创建和销毁会消耗很多的资源,当我们创建线程时,会发现cpu利用率很高,为了节省资源的使用,使用线程池是一个比较好的选择,当有任务需要执行时,随机分配给一条线程去执行,也可以删除任务,获取任务数量等 ...

  2. [.NET] 自己实现任务池(模仿线程池)

    线程池虽然好用,但限制也不少: (1)总觉得默认的 MaxThread 小了一点,每次使用都要手工调大= = (2)任务不能等待完成 (3)任务一旦加入不能取消,甚至不知道是正在排队/正在执行/执行完 ...

  3. 线程池ThreadPoolExecutor源码解读研究(JDK1.8)

    一.什么是线程池 为什么要使用线程池?在多线程并发开发中,线程的数量较多,且每个线程执行一定的时间后就结束了,下一个线程任务到来还需要重新创建线程,这样线程数量特别庞大的时候,频繁的创建线程和销毁线程 ...

  4. JAVA 线程池之Callable返回结果

    本文介绍如何向线程池提交任务,并获得任务的执行结果.然后模拟 线程池中的线程在执行任务的过程中抛出异常时,该如何处理. 一,执行具体任务的线程类 要想 获得 线程的执行结果,需实现Callable接口 ...

  5. 合理使用线程池 ThreadPool.QueueUserWorkItem()

    //==>自建线程 new Thread(() => { //线程任务 Console.WriteLine(Thread.CurrentThread.ManagedThreadId); } ...

  6. 使用线程池模拟处理耗时任务,通过websocket提高用户体验

    前言 在文章开始之前,询问一下大家平时工作中后端处理批量任务(耗时任务)的时候,前端是如何告知用户任务的执行情况的? 楼主对这个问题想了下,决定使用websokect将这一过程展现给用户. 于是就有了 ...

  7. 自定义ThreadPoolExecutor带Queue缓冲队列的线程池 + JMeter模拟并发下单请求

    .原文:https://blog.csdn.net/u011677147/article/details/80271174 拓展: https://github.com/jwpttcg66/GameT ...

  8. 模拟登陆,selenium,线程池

    一 . 模拟登陆案例(识别验证码)  1 . 打码平台 - 云打码 : www.yundama.com  使用步骤 : - 注册两个账户,普通用户和开发者用户 : - 登陆 普通用户查看余额 登陆开发 ...

  9. Python进阶----异步同步,阻塞非阻塞,线程池(进程池)的异步+回调机制实行并发, 线程队列(Queue, LifoQueue,PriorityQueue), 事件Event,线程的三个状态(就绪,挂起,运行) ,***协程概念,yield模拟并发(有缺陷),Greenlet模块(手动切换),Gevent(协程并发)

    Python进阶----异步同步,阻塞非阻塞,线程池(进程池)的异步+回调机制实行并发, 线程队列(Queue, LifoQueue,PriorityQueue), 事件Event,线程的三个状态(就 ...

随机推荐

  1. struts2注解redirect传递参数解决方案时,中国的垃圾问题

    struts2注解redirect传递参数解决方案时,中国的垃圾问题 试过很多方法  tomcat 编码  .字符串转换 .URLEncoder  .. 但是,没有解决方案,然后仔细阅读   stru ...

  2. HDOJ 4416 Good Article Good sentence

    题解转自:http://blog.csdn.net/dyx404514/article/details/8807440 2012杭州网络赛的一道题,后缀数组后缀自己主动机都行吧. 题目大意:给一个字符 ...

  3. SQL Server 2012的附件失败,与硬链接的问题

    1.我在系统上做了硬链接,也就是把C盘的某个目录,映射为D盘. 2.把数据库文件mdf和ldf放入D盘.结果,SQL Server的企业管理器,无法从D盘里加载mdf或ldf文件,并且在目录下无法显示 ...

  4. 仿javascript中confirm()方法的小插件

    10天没有写博客了,不知道为什么,心里感觉挺不舒服的,可能这是自己给自己规定要去完成的事情,没有按照计划执行,总会心里不怎么舒服.最近事情挺多的,终于今天抽空来更新一下博客了. 今天写的是一个小插件. ...

  5. Jumony快速抓取网页

    Jumony快速抓取网页 --- Jumony使用笔记--icode   作者:郝喜路   个人主页:http://www.cnicode.com      博客地址:http://haoxilu.c ...

  6. ext日期加减任意天数

    1.Ext.util.Format.date(new Date().add(Date.DAY, 5), 'Y-m-d'), 'Y-m-d') 2.Ext.util.Format.date(new Da ...

  7. Asp.Net Web Api 接口

    如何让你的 Asp.Net Web Api 接口,拥抱支持跨域访问.   由于 web api 项目通常是被做成了一个独立站点,来提供数据,在做web api 项目的时候,不免前端会遇到跨域访问接口的 ...

  8. T4模版

    T4模版 这讲适合所有的MVC程序 很荣幸,我们的系统有了体验的地址了.演示地址 之前我们发布了一个简单的代码生成器,其原理就是读取数据库的表结构,生成文本的一个方式来生成代码! 为了替代重复的劳动, ...

  9. 基于python的《Hadoop权威指南》一书中气象数据下载和map reduce化数据处理及其可视化

    文档内容: 1:下载<hadoop权威指南>中的气象数据 2:对下载的气象数据归档整理并读取数据 3:对气象数据进行map reduce进行处理 关键词:<Hadoop权威指南> ...

  10. 使用TotoriseSVN的分支/标签功能

    使用TotoriseSVN的分支/标签功能 http://blog.sina.com.cn/s/blog_5383588c0100o1oo.html 原来在新建一个项目文件夹后,再把Trunk.Bra ...