参考文章:

[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. SQL data reader reading data performance test

    /*Author: Jiangong SUN*/ As I've manipulated a lot of data using SQL data reader in recent project. ...

  2. mysql utf8mb4与emoji表情

    一 什么是Emoji emoji就是表情符号:词义来自日语(えもじ,e-moji,moji在日语中的含义是字符) 表情符号现已普遍应用于手机短信和网络聊天软件. emoji表情符号,在外国的手机短信里 ...

  3. centos6的安装

      centos6的安装,一步一图,有图有真相     打开虚拟机VMware,点击文件,选择[新建虚拟机],如图所示

  4. 用一条SQL语句取出第 m 条到第 n 条记录的方法

    原文:用一条SQL语句取出第 m 条到第 n 条记录的方法   --从Table 表中取出第 m 条到第 n 条的记录:(Not In 版本)       *    FROM Table     id ...

  5. 四个漂亮的CSS样式表

    1. 单像素边框CSS表格 这是一个非经常常使用的表格样式. 源码: <!-- CSS goes in the document HEAD or added to your external s ...

  6. 更新部分字段 NHibernate

    更新部分字段 NHibernate 概述: 在有些情况下,我只想更新记录中的一个字段的值.比如:浏览完这条记录后,我把其中的是否浏览置为1. Nhibernate中提供了Native SQL,其中有一 ...

  7. sql常用语句汇总

    --创建数据库 USE yuju CREATE database YuJu on primary ( name='YuJu', filename='B:\ceshi数据库\YuJu.mdf', max ...

  8. 初识Identity

    初识Identity 摘要 通过本文你将了解ASP.NET身份验证机制,表单认证的基本流程,ASP.NET Membership的一些弊端以及ASP.NET Identity的主要优势. 目录 身份验 ...

  9. 为什么使用Ninject?

    Ninject 3 学习笔记 一.为什么使用Ninject? 分类: 程序2012-11-10 19:23 2209人阅读 评论(0) 收藏 举报 c#iocNinject框架注入 最近在使用IoC进 ...

  10. vj1011:记忆化搜索

    vj1011:记忆化搜索 这题就是很简单的记忆化搜索即可,和经典题目滑雪简直一模一样 对于记忆化搜索,我也是暑假看了ccy大神的题解才有所领悟的 其实也就是DFS+mark 主要的部分 int sea ...