`
sunnylocus
  • 浏览: 869642 次
  • 性别: Icon_minigender_1
  • 来自: 美国图森
社区版块
存档分类
最新评论

处理线程泄露

    博客分类:
  • Java
阅读更多

   当一个单线程化的控制台程序因为未捕获的异常终止的时候,程序停止运行,并生了栈追踪,这与典型的程序输出不同,当一个程序发生了异常说明有不稳定的因素存在。如果并发程序中线程失败就没那么容易发现了。栈追踪可能会从控制台输出,但是没有人会去一直在看控制台,并且,当线程失败的时候,应用程序可能看起来仍在工作。就象程序能跑在50个线程池上,也能够跑在49个线程的线程池上,区别在于50个人干的活要比49个人干的活要多的多。

  导致线程死亡的的最主要的原因是RuntimeException。因为这些异常表明一个程序错误或者不可修复的错误,它们不着顺着栈的调用传递,此时,默认的行为是在控制台打印栈追踪的信息,并终止线程。

  我们举个例子,将奴隶主比作是你写的程序,奴隶比作是线程。假如你是奴隶主,你手下有5名奴隶,你分派他们一项任务去将不断开采来的石头搬到某个地方。如果中途有奴隶逃跑,那么搬运石头的效率就会下降,如果你没有措施发现奴隶逃跑,最后连一个奴隶也没有了,没有人再去搬石头了。当你发现程序有问题,比如程序刚启动的时候处理速度很快,以后越跑越慢,最后完全停止了,你可能不知道问题出在哪儿,其实这都是因为线程泄露引起的。想解决奴隶逃跑问题,不难,给每个奴隶戴上个报警器,一逃跑报警器就给你发信息,告诉哪个奴隶,因为什么原因逃跑了,可以根据需要再增加一名奴隶,让搬石头的奴隶数量始终维持在5名或着将信息记录到文件,便于分析导致线程泄露的原意改进程序。ok,我们用代码说话

1、定义好报警器

package com.bill99.thread.test;

import java.lang.Thread.UncaughtExceptionHandler;

//将泄露的线程信息输出到控制台
public class UEHLogger implements UncaughtExceptionHandler {
	public void uncaughtException(Thread t, Throwable e) {
		System.out.println(String.format("不好了,有奴隶逃跑了!奴隶姓名:%1$s,编号:%2$s,逃跑原因:%3$s", t.getName(),t.getId(),e.getMessage()));
		System.out.println("还剩"+HelotPool.helotPool.getActiveCount()+"个奴隶");
	}
}

  

2、我们先建立一个奴隶工厂,每名奴隶出工厂的时候都会有一个报警器

    

package com.bill99.thread.test;

import java.util.concurrent.ThreadFactory;
//奴隶制造工厂
public class HelotFactory implements ThreadFactory {
	private volatile int helotId=0;//奴隶编号
	//产生一个新奴隶
	public Thread newThread(Runnable r) {
		Thread helotThread = new Thread(r);
		helotThread.setName("helot-Thread-"+gethelotId());//设置奴隶姓名
		helotThread.setUncaughtExceptionHandler(new UEHLogger());//UEHLogger就是报警器
		return helotThread;
	}
	private int gethelotId(){
		return ++helotId;
	}
}

 3、奴隶逃跑测试,看看是否会触发报警器

package com.bill99.thread.test;

import java.util.concurrent.ThreadFactory;
//奴隶逃跑测试
public class HelotEscapeTest {
	private ThreadFactory factory = new HelotFactory();
	private Thread helotThread = null;
	
	public HelotEscapeTest(){
		Runnable task = new Runnable() {
			int stoneNum=1;
			public void run() {
				while(!Thread.interrupted()){
					System.out.println(helotThread.getName()+" 搬第"+stoneNum+"块石头..");
					stoneNum++;
					try{
						Thread.sleep(500);
					} catch(InterruptedException e){e.printStackTrace();}
					if(stoneNum>100){
						throw new RuntimeException("又饿又累没力气搬石头了");
					}
				}
			}
		};
		helotThread = factory.newThread(task);
	}
	//开始干活
	public void startWork(){
		helotThread.start();
	}
	public static void main(String[] args) {
		HelotEscapeTest test = new HelotEscapeTest();
		test.startWork();
	}
}

 运行程序后,奴隶在搬完100块石头后不干了,报警器给出提示信息

   不好了,有奴隶逃跑了!奴隶姓名:helot-Thread-1,编号:7,逃跑原因:又饿又累没力气搬石头了

这样我就能找出线程泄露的原因了。如果在线程池中发生了泄露是否也能记录?

4、奴隶池测试

package com.bill99.thread.test;

import java.util.Random;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class HelotPoolTest {
	
	public static ThreadPoolExecutor helotPool;
	private int helotNum= 5;  //奴隶数
	private Random random = new Random(100);
	
	private BlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>();
	
	public HelotPoolTest() {
		ThreadFactory factory = new HelotFactory();
		helotPool = new ThreadPoolExecutor( helotNum,helotNum,1000,TimeUnit.SECONDS,queue,factory);
	}
	//分配任务
	public void assignTask(){
		final int MAX=100;
		final int MIN=10;
		Runnable task = null;
		for(int j=0;j<20;j++){
			task = new Runnable() {
				int stoneNum = random.nextInt(MAX - MIN + 1) + MIN;// 生成10~100范围的随机数
				public void run() {
					for (int i = 1; i <= stoneNum; i++) {
						System.out.println(Thread.currentThread().getName() + " 搬完"+ i + "块石头");
						if (i == 60) {
							throw new RuntimeException("搬完第60块石头不干了");
						}
						try{
							Thread.sleep(100);//休息下
						}catch(InterruptedException e){e.printStackTrace();}
					}
				}
			};
			queue.add(task);
		}
	}
	//开始干活
	public void startWork(){
		helotPool.prestartAllCoreThreads();
	}
	public static void main(String[] args) {
		HelotPoolTest pool = new HelotPoolTest();
		pool.assignTask();
		pool.startWork();
	}
}

 程序启动,用Jprofiler监控,刚启动时会有5名奴隶干活不一会就会有线程退出,最后5个线程全部退,报警器对每个线程退出都能记录到导致线程退出的原因。标准的Executor实现是:

在需求不高时回收空闲的线程,在需求增加时添加新的线程,如果任务抛出了异常,就会用一个全新的工作线程取代出错的那个。

JDK文档是这么说的,不过通过Jprofiler监控只有在5名奴隶全部逃跑,没人干活的时候ThreadPoolExecutor才会生成一个新线程继续搬石头,并不是只要一个线程退出就会马上生成新线程去代替。

 

 

1
0
分享到:
评论
4 楼 陈星恒o 2014-12-10  
很感谢楼主,举的例子
3 楼 sunnylocus 2010-02-03  
zhangthe9 写道

是你少敲了几个字符

在机器都测试通过的,然后再粘贴过来的,你说那个类中少 HelotPool ?
2 楼 zhangthe9 2010-02-03  

是你少敲了几个字符
1 楼 zhangthe9 2010-02-03  
HelotPool 在哪

相关推荐

    worker线程处理时,同时刷新对话框消息

    所以要处理线程同时即时刷新界面要用SendMessage,它是一同步发送消息,会等处理完成才返回,即一SendMessage就会进入Refresh函数 2.而多线程函数的使用中可能出现以下问题,如果用 CWinThread * pthread=...

    MFC中解决子线程中打开非模态对话框内存泄漏实例(VC++2008)

    子线程中打开非模式对话框内存泄漏问题 这个问题困扰已久 网上没有完整的解决方案;现将实例源代码分享给大家 希望对您有帮助 (代码是VS2008下编写的) 问题原因: 对话框的默认关闭方式模式对话框关闭 而现在是...

    Java理论与实践:嗨,我的线程到哪里去了?

    像对付许多风险一样,防止线程泄漏的最佳方法是预防和检测相结合;注意有可能抛出RuntimeException的地方(如调用外来代码时),并使用ThreadGroup提供的uncaughtException处理程序来在线程异常终止时进行检测。

    C语言如何正确的终止正在运行的子线程

    最近开发一些东西,线程数非常之多,当用户输入Ctrl+C的情形下,默认的信号处理会把程序退出,这时有可能会有很多线程的资源没有得到很好的释放,造成了内存泄露等等诸如此类的问题,本文就是围绕着这么一个使用场景...

    闻怡洋VC专题教程ActiveX控件开发 进程/线程控制 文件操作 内存管理

    |------ 3.3 内存泄露检查 |------ 3.4 异常捕捉与处理 +-- 第四章 进程/线程控制 |------ 4.1 为什么需要多进程/线程 |------ 4.2 进程控制 |------ 4.3 线程控制 |------ 4.4 进程/线程间同步 +------ 4.5 进程间...

    java8源码-QuantaAndroidStu2020:多线程和网络请求直播课源代码

    子线程负责处理耗时操作 1.线程的几种写法(匿名接口类/(java8支持lambda简洁写法) 2.handler 、runOnUiThread()(普通写法的内存泄露情况 原理及优化方法 ) 3.asyncTask //子线程 调用doInBackground() 、 // ...

    XP下的PortReady1.6多线程的端口扫描

    │的功能,可以用来快速地获取端口标识(Banner),内定对80端口标识进行特别处理,能方便地获取Web│ │Server类型。PortReady 1.6同时提供Windows图形版本和控制台版本,不管是在图形环境下,还是在│ │控制台模式中...

    threadjs-lib:nodejs多线程

    lib --save在主线程/子线程之间进行数据通信轻量级的v8线程(非nodejs线程)子线程的主动挂起,使用模拟同步操作主线程且且所有子线程都退出后,主线程也会退出用libuv挂载的事件可以正确处理使用npm test进行测试,...

    IOCP封装类,用VC6.0封装的

    代码更加稳定,取消监听线程的异常处理 删减一些不必要且会引起异常的代码 客户端: 同样采用0缓冲,没有接收数据大小的限制 优化一些代码,基本稳定 IOCP_V3.rar(20110207) 服务端: 修复服务端代码一些不严密的地方 ...

    .NET资源泄露与处理方案知识点分享

    句柄泄露:Socket或线程。 用户对象泄露:移除的对象未释放。 二、具体实例 1. 内存泄漏 很常见的现象是分不清哪些对象需要释放,对于控件、Stream等一些非托管资源也只管新增,却没有释放,功能是实现了,却埋了...

    订单管理系统:多种维度、多种渠道订单管理,自动化处理,及退换货处理。.zip

    Java是一种高性能、跨平台的面向...自动内存管理(垃圾回收): Java具有自动内存管理机制,通过垃圾回收器自动回收不再使用的对象,使得开发者不需要手动管理内存,减轻了程序员的负担,同时也减少了内存泄漏的风险。

    Java HttpURLConnection超时和IO异常处理

    主要介绍了Java HttpURLConnection超时和IO异常处理的相关资料,需要的朋友可以参考下

    Handler对象中使用匿名内部类或非静态内部类正确地释放消息避免内存泄漏或增加Native内存

    Handler对象中使用匿名内部类或非静态内部类正确地释放消息避免内存泄漏或增加Native内存,在Android中,Handler对象通常会被用来在主线程(UI线程)中处理消息,以更新UI界面。当我们在Handler对象中使用匿名内部类...

    C#开发常见问题清单总结与入门常见问题.docx

    技巧8:利用C#垃圾回收机制减少内存泄漏风险 技巧9:使用IDisposable接口与using语句管理非托管资源 4. 并发与多线程编程 技巧10:线程同步与并发控制 技巧11:避免死锁的策略与设计模式 技巧12:线程安全编程与锁...

    java核心面试

    多线程 线程进程 线程状态 线程状态的改变 sql :临时表、游标、存贮过程、触发机制http://www.cnblogs.com/SkySoot/archive/2012/04/09/2439190.html jvm工作原理 JVM中类的装载是由ClassLoader和它的子类来实现...

    java核心面试技术点

    多线程 线程进程 线程状态 线程状态的改变 sql :临时表、游标、存贮过程、触发机制http://www.cnblogs.com/SkySoot/archive/2012/04/09/2439190.html jvm工作原理 JVM中类的装载是由ClassLoader和它的子类来实现...

    一个进程池的服务器程序

    总的来说,思想是让子进程accept并处理请求,父进程通过子进程发来的信息控制请求数与子进程数之间的关系。 代码如下: 代码如下: #include #include #include #include #include #include #include #...

    OA管理系统。流程审批、用户管理、文件上传下载、消息处理。SpringMVC+MyBatis.zip

    Java是一种高性能、跨平台的面向...自动内存管理(垃圾回收): Java具有自动内存管理机制,通过垃圾回收器自动回收不再使用的对象,使得开发者不需要手动管理内存,减轻了程序员的负担,同时也减少了内存泄漏的风险。

    多线程程序的信息抹除和降密安全策略 (2010年)

    为了满足多线程环境下实际应用程序故意释放敏感信息以及加强信息机密性的需求,基于强互模拟等价的方式定义能够同时处理信息降密和抹除的安全属性.该属性能控制被释放的机密信息的内容,使得降密机制不会被攻击者...

    java,c/c++,php,c#安全编码规范

    1 业务安全编码规范 6 1.1 输入验证和数据合法性校验 6 1.1.1 避免SQL注入 6 1.1.2 避免XML注入 6 1.1.3 避免跨站点脚本(XSS) 7 ...2.8.2 在序列化过程中避免内存和资源泄漏 29 3 其他参考资料 30

Global site tag (gtag.js) - Google Analytics