参考文章:

[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. C#遍历文件名

    遍历文件名程序 //////////////////第一种方法///////////// static ArrayList GetAllFiles(string path) { ArrayList r ...

  2. ubuntu下的词典的安装

    因为从事开发,安装一个词典是很有必要,文中介绍安装openyoudao和stardic两个软件的方法 一.openyoudao的安装 因为是由window转来学ubuntu的,所以总是想安装和wind ...

  3. 微软BI 之SSIS 系列 - 使用 Script Task 访问非 Windows 验证下的 SMTP 服务器发送邮件

    原文:微软BI 之SSIS 系列 - 使用 Script Task 访问非 Windows 验证下的 SMTP 服务器发送邮件 开篇介绍 大多数情况下我们的 SSIS 包都会配置在 SQL Agent ...

  4. Solr多核心及分词器(IK)配置

    Solr多核心及分词器(IK)配置   多核心的概念 多核心说白了就是多索引库.也可以理解为多个"数据库表" 说一下使用multicore的真实场景,比若说,产品搜索和会员信息搜索 ...

  5. 让.NET程序快速释放内存的办法

    原文:让.NET程序快速释放内存的办法 公司里的一个程序,经过了N个人的手后发现上了生产内存会一直涨,直到物理内存几乎被占用完毕后突然就下降下来(估计是GC给释放了),然后再一直涨.这个程序主要是对字 ...

  6. 如何给非AppCompatActivity添加Toolbar?--关于5.0新特性兼容5.0以下设备的探索

    Android支持包22.1引进了AppCompatDelegate 最新22.1版本的支持包引入了大量酷炫的新特性,这些特性将允许我们轻易地将材料设计/API 21+的特性应用到之前的那些老的,不兼 ...

  7. 事件处理(Event Handlers) ng-click操作

    事件处理(Event Handlers) ng-click操作 step 10 本文主要通过介绍ng-click方法来对angularjs中的事件处理方法做个了解. 1.切换目录 git checko ...

  8. Coding the Matrix Week 1 The Vector Space作业

    Coding the Matrix: Linear Algebra through Computer Science Applications 本周的作业较少,只有一个编程任务hw2.作业比较简单,如 ...

  9. Knockout 是什么?

    翻译:Knockout 轻松上手 - 1 Knockout 是什么? 原文名称:KnockoutJS Starter Knockout 是一个非常棒的脚本库,可是我发现许多人并不了解它,所以,思胜翻译 ...

  10. [转]iOS Tutorial – Dumping the Application Heap from Memory

     Source:https://blog.netspi.com/ios-tutorial-dumping-the-application-heap-from-memory/ An essential ...