- 浏览: 48940 次
- 性别:
- 来自: 常州
-
最新评论
-
yi_17328214:
:idea:
js实现图片下拉列表 -
yi_17328214:
<form name="myform" ...
js实现图片下拉列表 -
seven_cuit:
今天阿里巴巴笔试就问了这个问题,竟然漏了枚举
JDK1.5新特性简介
了解JAVA多线程编程的人都知道,要产生一个线程有两种方法,一是类直接继承Thread类并实现其run()方法;二是类实现Runnable接口并实现其run()方法,然后新建一个以该类为构造方法参数的Thread,类似于如下形式: Thread t=new Thread(myRunnable)。而最终使线程启动都是执行Thread类的start()方法。
在JAVA中,一个线程一旦运行完毕,即执行完其run()方法,就不可以重新启动了。此时这个线程对象也便成了无用对象,等待垃圾回收器的回收。下次想再启动这个线程时,必须重新new出一个线程对象再start之。频繁地创建和销毁对象不仅影响运行效率,还可能因无用线程对象来不及被回收而产生大量的垃圾内存,在存储空间和处理速度都相对受限的移动平台上这种影响尤为显著。那么,能否重新设计一种线程类,使其能够被反复启动而无需频繁地创建和销毁对象呢?
当然可以。下面我就介绍一下对这个“可重启线程”类的设计。
首先必须明确,如果仍是把想要线程去做的任务直接放在线程的run()方法中,是无论如何无法达成目的的,因为就像上面已经说的,JAVA的线程类一旦执行完run()方法就无法再启动了。所以唯一可行的办法是,把用户程序要做的run()方法(不妨称作“用户过程”)套在线程实际的run()方法内部的while循环体内,当用户过程执行完后使线程wait。当调用restart方法重启线程时,实际就是唤醒等待中的线程使之开始下一次while循环。大致的思想确定了,下面的代码就很好理解了:
public class ReusableThread implements Runnable {
//线程状态监听者接口
public interface ThreadStateListener {
public abstract void onRunOver(ReusableThread thread);//当用户过程执行完毕后调用的方法
}
public static final byte STATE_READY=0; //线程已准备好,等待开始用户过程
public static final byte STATE_STARTED=1; //用户过程已启动
public static final byte STATE_DESTROYED=2; //线程最终销毁
byte mState; //标示可重启线程的当前状态
Thread mThread; //实际的主线程对象
Runnable mProc; //用户过程的run()方法定义在mProc中
ThreadStateListener mListener; //状态监听者,可以为null
/** Creates a new instance of ReusableThread */
public ReusableThread(Runnable proc) {
mProc = proc;
mListener = null;
mThread = new Thread(this);
mState = STATE_READY;
}
public byte getState() {return mState;}
public void setStateListener(ThreadStateListener listener) {
mListener = listener;
}
/**可以在处于等待状态时调用该方法重设用户过程*/
public synchronized boolean setProcedure(Runnable proc) {
if (mState == STATE_READY) {
mProc = proc;
return true;
}
else
return false;
}
/**开始执行用户过程*/
public synchronized boolean start() {
if (mState == STATE_READY) {
mState = STATE_STARTED;
if (!mThread.isAlive()) mThread.start();
notify(); //唤醒因用户过程执行结束而进入等待中的主线程
return true;
}
else
return false;
}
/**结束整个线程,销毁主线程对象。之后将不可再次启动*/
public synchronized void destroy() {
mState = STATE_DESTROYED;
notify();
mThread = null;
}
public void run() {
while (true) {
synchronized (this) {
try {
while (mState != STATE_STARTED) {
if (mState == STATE_DESTROYED) return;
wait();
}
} catch(Exception e) {e.printStackTrace();}
}
if (mProc != null) mProc.run();
if (mListener != null) mListener.onRunOver(this); //当用户过程结束后,执行监听者的onRunOver方法
synchronized (this) {
if (mState == STATE_DESTROYED) return;
mState = STATE_READY;
}
}
}
}
代码很好懂是不是?但是要解释一下为什么要有一个“状态监听者”接口。有时候我们可能想要在用户过程结束后得到一个及时的通知,好进行另外的处理,这时状态监听者的onRunOver方法就有了用处。一个直观的例子是,在下面要提到的“线程池”类中,一个可重启线程执行完一次用户过程后应当自动回收入池,这时就可以把回收入池的动作放在onRunOver方法中,而它的参数就是该可重启线程对象,于是就可以把参数所指示的对象回收进线程池中。
至于线程池类,其实就是以前提到的对象池类的一个子类,其中的对象全是ReusableThread类的。另外它实现了ReusableThread.ThreadStateListener接口,以便可以在用户过程结束时及时收到通知,执行回收线程的工作:
public class ThreadPool extends ObjectPool implements ReusableThread.ThreadStateListener {
public static final int DefaultNumThreads = 16; //默认池容量
public ReusableThread getThread() {
return (ReusableThread)fetch();
}
public void onRunOver(ReusableThread thread) {
recycle(thread); //当用户过程结束时,回收线程
}
private void init(int size) {
ReusableThread thread;
//初始化线程池内容
for (int i=0; i<size; i++) {
thread = new ReusableThread(null);
thread.setStateListener(this);
setElementAt(thread, i);
}
}
public ThreadPool(int size) {
super(size);
init(size);
}
public ThreadPool() {
super(DefaultNumThreads);
init(DefaultNumThreads);
}
}
当然,还有一些可能需要添加的功能,因为既然只是比普通线程多了一个可重启的“增强”型线程类,那么原来Thread类具有的功能也应该具有,比如线程的sleep()。不过那些比较简单,这里就略去了。
下面编写测试程序。我准备这样进行:并不用到线程池类,而是对对象池类和可重启线程类进行联合测试,该对象池中的对象所属的类CharEmitter实现了Runnable接口和线程状态监听者接口,并且含有一个可重启线程成员对象,它并不包含在任何线程池对象中,而是独立使用的。当此线程的用户过程(定义在CharEmitter类中)结束后,onRunOver方法执行回收本CharEmitter对象入池的动作。这样就同时起到了间接测试线程池类的作用,因为它与对象池的区别也不过是在onRunOver中执行回收动作而已。
还是直接上代码说得清楚:
TestThreadPool.java :
/**字符放射器*/
class CharEmitter implements Runnable, ReusableThread.ThreadStateListener {
char c; //被发射的字符
boolean[] isEmitting; //标示某字符是否正被发射(直接以字符对应的ASCII码作下标索引)
ReusableThread thread; //可重启线程对象
ObjectPool myHomePool; //为知道应把自己回收到哪里,需要保存一个到自己所在对象池的引用
CharEmitter(ObjectPool container, boolean[] isCharEmitting) {
isEmitting=isCharEmitting;
myHomePool=container;
thread=new ReusableThread(this); //新建可重启线程对象,设其用户过程为CharEmitter类自己定义的
}
/**开始“发射”字符*/
public void emit(char ch) {
//字符被要求只能是'0'到'9'之间的数字字符
if (ch>='0' && ch<='9') {
c=ch;
}
else c=' ';-
-
文章搜索: 点击制作chm打包电子书教程
【在本站快速建博,与同行交流】
p; thread.start(); //启动线程
}
public void run() {
if (c==' ') return; //若不是数字字符直接结束
//为便于观察,不同数字之前的空格数目不同,以便将其排在不同列上
int spaceLen=c-'0';
StringBuffer s=new StringBuffer(spaceLen+1);
for (int i=0; i<spaceLen; i++) s.append(' ');
s.append(c);
while (isEmitting[c]) {
System.out.println(s); //不断地向屏幕写字符
}
}
/**实现线程状态监听者接口中的方法*/
public void onRunOver(ReusableThread t) {
myHomePool.recycle(this); //回收自身入池
}
}
public class TestThreadPool {
public static void main(String[] args) {
// TODO Auto-generated method stub
//标示字符是否正被发射的标志变量数组
boolean[] isEmitting=new boolean[256];
for (int i=0; i<256; i++) isEmitting[i]=false;
ObjectPool emitters=new ObjectPool(10); //新建对象池,容量为10
for (int i=0; i<10; i++) {
//用CharEmitter对象填满池子
emitters.setElementAt(new CharEmitter(emitters, isEmitting), i);
}
byte[] c=new byte[1];
CharEmitter emitter;
while(true) {
try {
System.in.read(c); //从键盘读入一个字符,以回车键表示输入结束
} catch(Exception e) {e.printStackTrace();}
if (isEmitting[c[0]]) {
isEmitting[c[0]]=false; //若字符正被发射,则结束其发射
}
else {
isEmitting[c[0]]=true;
emitter=(CharEmitter)emitters.fetch(); //向池中索取一个CharEmitter对象
emitter.emit((char)c[0]); //发射用户输入的字符
}
}
}
}
执行后,从键盘上敲进0到9之间的任意数字并按回车,之后会不断地在屏幕上滚动显示该数字;再次输入同样的数字则不再显示该数字。同时存在多个数字被发射时,可以明显看出不同数字的显示是交错进行的,这正是由于虚拟机在各线程间调度的结果。运行结果表明,我们设计的类功能完全正确。
在以后要说的J2ME中蓝牙通讯的辅助类中,将会看到,线程池与可重启线程起到了不可替代的作用。
发表评论
-
zt-Java异常处理机制的详细讲解和使用技巧
2010-08-07 14:18 7551. 异常机制 1.1 异 ... -
junit 基本教程
2010-07-22 11:35 1016Eclipse中配置junit 在要使用JUNIT的p ... -
zt-ssh优缺点分析
2010-06-18 14:20 839字号:大 中 小 Struts跟Tomcat、Turb ... -
MySQL+Hibernate下连接空闲8小时自动断开问题解决方案
2010-06-18 13:46 1395Hibernate使用C3P0的连接池 ... -
ZT-c3p0的配置解释
2010-06-18 10:49 1191找到了一个关于c3p0的配置 <c3p0-confi ... -
JDK和Tomcat环境变量配置
2010-04-24 12:31 806JDK环境变量配置: 如果你的JDK安装在C盘里 ... -
zt- synchronized 关键字
2010-01-25 15:56 747synchronized 关键字, ... -
ZT-JDK中的URLConnection使用总结
2010-01-05 13:50 751针对JDK中的URLConnection连接Servlet的问 ... -
怎样用Java来获取真实的IP地址
2010-01-03 16:23 1366摘录自:http://www.blogjava.net/wan ... -
tomcat内存溢出总结(转)
2009-12-22 16:51 668在生产环境中tomcat内存设置不好很容易出现内存溢出。造成内 ... -
get/post时中文乱码问题的解决办法
2009-11-21 13:13 1792form有2中方法把数据提 ... -
基于表单的文件上传
2009-11-09 11:34 17891. 基于表单 ... -
struts2+spring简单配置
2009-11-04 09:35 7851,修改web.xml <!-- 配置spring 开始 ... -
java中的内存分配机制
2009-10-24 12:28 779Java把内存划分成两种:一种是栈内存,一种是堆内存。 在函 ... -
java 中参数的传递
2009-10-23 17:46 709public static void main(Str ... -
BEA WebLogic Server® 9.2 中文帮助网站
2009-10-10 15:48 747http://edocs.weblogicfans.net/w ... -
JRE和JDK的区别浅析
2009-09-30 14:43 820JRE和JDK的含义是什么呢 ... -
Hibernate 调用JDBC执行存储过程
2009-09-28 11:04 1388public boolean procMemberInfo(i ... -
SPRING中属性SCOPE的prototype是什么意思
2009-09-28 09:50 5579默认情况下,从bean工厂所取得的实例为Singleton(b ... -
Spring有四种Bean封装机制
2009-09-28 09:25 1204Spring有四种Bean封装机制:Bean Wrapper机 ...
相关推荐
.......................................JAVA线程、线程池资料----下载不扣分,回帖加1分,欢迎下载,童叟无欺JAVA线程、线程池资料----下载不扣分,回帖加1分,欢迎下载,童叟无欺JAVA线程、线程池资料----下载不...
`HashMap`在不同JDK版本间可能存在差异,例如在JDK 7及之前,`HashMap`是非线程安全的,而在JDK 8中进行了优化,引入了红黑树提高性能。`ConcurrentHashMap`是线程安全的Map实现,适用于多线程环境下的并发访问。 ...
合理利用AsyncTask、Runnable、Thread、Handler、Looper、线程池和线程同步机制,能帮助开发者设计出更加健壮和高效的Android应用。在实际开发中,应根据任务特性和需求,选择最适合的线程管理方式。通过Demo实践,...
为了解决这个问题,我们可以设计一个可重启的线程类,这正是`ReusableThread`类的目的所在。这个类允许我们反复启动同一个线程实例,避免了频繁创建和销毁线程对象,从而提高性能,特别是在资源有限的环境中,如移动...
3. **线程池设计**:了解线程池的基本架构,包括任务队列的实现、工作线程的管理和调度策略。 4. **同步机制**:线程池中可能会涉及到`std::mutex`、`std::condition_variable`等同步原语,用于保证线程安全,避免...
线程池是多线程编程中的重要工具,它允许开发者高效地管理和控制并发执行的线程,以提高系统性能和稳定性。在高并发场景下,线程池的使用显得尤为重要,因为它可以避免频繁创建和销毁线程所带来的开销。本文将深入...
【多线程 线程池 线程同步--DEMO】 软件平台:Visual Studio 2008 开发语言:C# 引用系统类:System.Threading System.Threading.ThreadPool 模拟多线程以及线程池的使用,对概念理解很有帮助的。
### 多线程编程线程池 #### 一、引言 在计算机科学领域,多线程编程是一种广泛采用的技术,旨在通过同时处理多个任务来提高应用程序的性能和响应速度。然而,创建和销毁线程的过程是相对昂贵的,尤其是在处理大量...
在C#编程中,线程和线程池是并发编程中的关键概念,特别是在开发Windows桌面应用程序(Winform)时,为了提升程序的响应性和效率,理解并熟练运用这些技术至关重要。本文将深入探讨如何在Winform应用中使用异步多...
根据给定的信息,本文将详细解析C#中的线程池实现方法,并重点介绍如何通过Mutex与Interlocked等机制来管理线程同步。 ### C#线程池的基本概念 线程池是C#中用于管理线程的一种高效机制,它允许程序在运行时动态地...
此文档是: 基于简单线程池概念的JAVA服务器端应用 附有连接ORACLE数据库等简单操作. 操作描述: 服务器启动后,会启动10个子线程运行.(配合客户端10个请求进行模拟,控制台输出模拟过程) 服务器主程序进入一个有...
2. `maximumPoolSize`:最大线程池大小,表示线程池可容纳的最大并发线程数。当提交到线程池的任务数量超过核心线程数时,线程池会创建新的线程,直到线程总数达到`maximumPoolSize`。若继续提交任务,将进入任务...
线程池是一组预先创建并等待任务的线程,当有新任务到来时,可以从线程池中取出一个线程执行任务,提高系统的并发性能。在VC6中,可以通过`_beginthreadex`和`CloseHandle`等API函数创建和管理线程。 3. **Socket套...
Java线程池是一种高效管理并发任务的工具,它通过复用线程来减少创建和销毁线程的开销,从而提高系统性能。线程池的核心组成部分包括工作队列(Work Queue)、工作线程(Worker Threads)和任务调度器(Executor)。...
Java中的线程与线程池是程序设计中的关键概念,特别是在多任务并行处理和优化系统性能时。本文档深入探讨了这两个主题,旨在帮助开发者更好地理解和应用它们。 线程是为了充分利用CPU资源而引入的执行单元。在多...
本篇文章将详细探讨“常用多线程模板”以及“鱼刺类(Fork/Join框架)多线程线程池”的应用,结合具体的代码实例来帮助理解这些概念。 首先,多线程是指在一个程序中同时执行多个不同的线程,以实现并行处理。在...
【线程与线程池的概念】 ...以上就是利用单线程、多线程、线程池来设计扫描网络IP的程序设计要点,以及实现步骤和代码结构的解析。这样的设计可以高效地遍历大量IP,提高扫描效率,并确保用户界面的流畅性。
C#线程同步及线程池相关资料C#线程同步及线程池相关资料C#线程同步及线程池相关资料C#线程同步及线程池相关资料C#线程同步及线程池相关资料C#线程同步及线程池相关资料C#线程同步及线程池相关资料C#线程同步及线程池...
线程池是一种重要的多线程处理机制,它的主要目的是为了实现资源的最大化利用和高效的任务处理。在服务器应用程序中,如Web服务器、数据库服务器、文件服务器或邮件服务器,通常需要处理来自远程源的大量短期任务。...
在C#编程中,多线程和线程池是实现并发执行任务的关键技术,它们能够提升应用程序的性能和响应性。下面将详细讲解这两个概念及其应用。 **一、多线程** 多线程允许程序同时执行多个独立的任务,提高CPU利用率。在...