- 浏览: 333237 次
- 性别:
- 来自: 温州
文章分类
最新评论
-
helloworldlove:
Axis_UNZIP_PATH\Axis-version\we ...
3步把您的java程序转换为webservice -
hcqenjoy:
这个工具能再提供下吗 已经没办法下载了 谢谢
汉化 Flex Builder 3 帮助文档 -
NASa_CJ:
String source = HttpClientExamp ...
利用HttpClient获取网页内容 -
zlsj80:
下载地址无效了,楼主修正一下吧
汉化 Flex Builder 3 帮助文档 -
fykyx521:
下载地址都不能用了,是不过时了
汉化 Flex Builder 3 帮助文档
<noscript type="text/javascript"><!----></noscript><noscript src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript">
</noscript>
Java5增加了新的类库并发集java.util.concurrent,该类库为并发程序提供了丰富的API多线程编程在Java 5中更加容易,灵活。本文通过一个网络服务器模型,来实践Java5的多线程编程,该模型中使用了Java5中的线程池,阻塞队列,可重入锁等,还实践了 Callable, Future等接口,并使用了Java 5的另外一个新特性泛型。
简介
本文将实现一个网络服务器模型,一旦有客户端连接到该服务器,则启动一个新线程为该连接服务,服务内容为往客户端输送一些字符信息。一个典型的网络服务器模型如下:
1. 建立监听端口。
2. 发现有新连接,接受连接,启动线程,执行服务线程。 3. 服务完毕,关闭线程。
这个模型在大部分情况下运行良好,但是需要频繁的处理用户请求而每次请求需要的服务又是简短的时候,系统会将大量的时间花费在线程的创建销毁。Java 5的线程池克服了这些缺点。通过对重用线程来执行多个任务,避免了频繁线程的创建与销毁开销,使得服务器的性能方面得到很大提高。因此,本文的网络服务器 模型将如下:
1. 建立监听端口,创建线程池。
2. 发现有新连接,使用线程池来执行服务任务。
3. 服务完毕,释放线程到线程池。
下面详细介绍如何使用Java 5的concurrent包提供的API来实现该服务器。
初始化
初始化包括创建线程池以及初始化监听端口。创建线程池可以通过调用java.util.concurrent.Executors类里的静态方法 newChahedThreadPool或是newFixedThreadPool来创建,也可以通过新建一个 java.util.concurrent.ThreadPoolExecutor实例来执行任务。这里我们采用newFixedThreadPool方 法来建立线程池。
表示新建了一个线程池,线程池里面有10个线程为任务队列服务。
使用ServerSocket对象来初始化监听端口。
服务新连接
当有新连接建立时,accept返回时,将服务任务提交给线程池执行。
这里使用线程池对象来执行线程,减少了每次线程创建和销毁的开销。任务执行完毕,线程释放到线程池。
服务任务
服务线程ServiceThread维护一个count来记录服务线程被调用的次数。每当服务任务被调用一次时,count的值自增1,因此 ServiceThread提供一个increaseCount和getCount的方法,分别将count值自增1和取得该count值。由于可能多个 线程存在竞争,同时访问count,因此需要加锁机制,在Java 5之前,我们只能使用synchronized来锁定。Java 5中引入了性能更加粒度更细的重入锁ReentrantLock。我们使用ReentrantLock保证代码线程安全。下面是具体代码:
服务线程在开始给客户端打印一个欢迎信息,
然后使用ExecutorService的submit方法提交一个Callable的任务,返回一个Future接口的引用。这种做法对费时的任务非 常有效,submit任务之后可以继续执行下面的代码,然后在适当的位置可以使用Future的get方法来获取结果,如果这时候该方法已经执行完毕,则 无需等待即可获得结果,如果还在执行,则等待到运行完毕。
其中TimeConsumingTask实现了Callable接口
这里使用了Java 5的另外一个新特性泛型,声明TimeConsumingTask的时候使用了String做为类型参数。必须实现Callable接口的call函数, 其作用类似与Runnable中的run函数,在call函数里写入要执行的代码,其返回值类型等同于在类声明中传入的类型值。在这段程序中,我们提交了 一个Callable的任务,然后程序不会堵塞,而是继续执行dos.write("let's do soemthing other".getBytes());当程序执行到String result = future.get()时如果call函数已经执行完毕,则取得返回值,如果还在执行,则等待其执行完毕。
服务器端的完整实现
服务器端的完整实现代码如下:
运行程序
运行服务端,客户端只需使用telnet 127.0.0.1 19527 即可看到信息如下:
Java5增加了新的类库并发集java.util.concurrent,该类库为并发程序提供了丰富的API多线程编程在Java 5中更加容易,灵活。本文通过一个网络服务器模型,来实践Java5的多线程编程,该模型中使用了Java5中的线程池,阻塞队列,可重入锁等,还实践了 Callable, Future等接口,并使用了Java 5的另外一个新特性泛型。
简介
本文将实现一个网络服务器模型,一旦有客户端连接到该服务器,则启动一个新线程为该连接服务,服务内容为往客户端输送一些字符信息。一个典型的网络服务器模型如下:
1. 建立监听端口。
2. 发现有新连接,接受连接,启动线程,执行服务线程。 3. 服务完毕,关闭线程。
这个模型在大部分情况下运行良好,但是需要频繁的处理用户请求而每次请求需要的服务又是简短的时候,系统会将大量的时间花费在线程的创建销毁。Java 5的线程池克服了这些缺点。通过对重用线程来执行多个任务,避免了频繁线程的创建与销毁开销,使得服务器的性能方面得到很大提高。因此,本文的网络服务器 模型将如下:
1. 建立监听端口,创建线程池。
2. 发现有新连接,使用线程池来执行服务任务。
3. 服务完毕,释放线程到线程池。
下面详细介绍如何使用Java 5的concurrent包提供的API来实现该服务器。
初始化
初始化包括创建线程池以及初始化监听端口。创建线程池可以通过调用java.util.concurrent.Executors类里的静态方法 newChahedThreadPool或是newFixedThreadPool来创建,也可以通过新建一个 java.util.concurrent.ThreadPoolExecutor实例来执行任务。这里我们采用newFixedThreadPool方 法来建立线程池。
ExecutorService pool = Executors.newFixedThreadPool(10); |
表示新建了一个线程池,线程池里面有10个线程为任务队列服务。
使用ServerSocket对象来初始化监听端口。
private static final int PORT = 19527; serverListenSocket = new ServerSocket(PORT); serverListenSocket.setReuseAddress(true); serverListenSocket.setReuseAddress(true); |
服务新连接
当有新连接建立时,accept返回时,将服务任务提交给线程池执行。
while(true){ Socket socket = serverListenSocket.accept(); pool.execute(new ServiceThread(socket)); } |
这里使用线程池对象来执行线程,减少了每次线程创建和销毁的开销。任务执行完毕,线程释放到线程池。
服务任务
服务线程ServiceThread维护一个count来记录服务线程被调用的次数。每当服务任务被调用一次时,count的值自增1,因此 ServiceThread提供一个increaseCount和getCount的方法,分别将count值自增1和取得该count值。由于可能多个 线程存在竞争,同时访问count,因此需要加锁机制,在Java 5之前,我们只能使用synchronized来锁定。Java 5中引入了性能更加粒度更细的重入锁ReentrantLock。我们使用ReentrantLock保证代码线程安全。下面是具体代码:
private static ReentrantLock lock = new ReentrantLock (); private static int count = 0; private int getCount(){ int ret = 0; try{ lock.lock(); ret = count; }finally{ lock.unlock(); } return ret; } private void increaseCount(){ try{ lock.lock(); ++count; }finally{ lock.unlock(); } } |
服务线程在开始给客户端打印一个欢迎信息,
increaseCount(); int curCount = getCount(); helloString = "hello, id = " + curCount+"\r\n"; dos = new DataOutputStream(connectedSocket.getOutputStream()); dos.write(helloString.getBytes()); |
然后使用ExecutorService的submit方法提交一个Callable的任务,返回一个Future接口的引用。这种做法对费时的任务非 常有效,submit任务之后可以继续执行下面的代码,然后在适当的位置可以使用Future的get方法来获取结果,如果这时候该方法已经执行完毕,则 无需等待即可获得结果,如果还在执行,则等待到运行完毕。
ExecutorService executor = Executors.newSingleThreadExecutor(); Future <String> future = executor.submit(new TimeConsumingTask()); dos.write("let's do soemthing other".getBytes()); String result = future.get(); dos.write(result.getBytes()); |
其中TimeConsumingTask实现了Callable接口
class TimeConsumingTask implements Callable <String>{ public String call() throws Exception { System.out.println("It's a time-consuming task, you'd better retrieve your result in the furture"); return "ok, here's the result: It takes me lots of time to produce this result"; } } |
这里使用了Java 5的另外一个新特性泛型,声明TimeConsumingTask的时候使用了String做为类型参数。必须实现Callable接口的call函数, 其作用类似与Runnable中的run函数,在call函数里写入要执行的代码,其返回值类型等同于在类声明中传入的类型值。在这段程序中,我们提交了 一个Callable的任务,然后程序不会堵塞,而是继续执行dos.write("let's do soemthing other".getBytes());当程序执行到String result = future.get()时如果call函数已经执行完毕,则取得返回值,如果还在执行,则等待其执行完毕。
服务器端的完整实现
服务器端的完整实现代码如下:
package com.andrew; import java.io.DataOutputStream; import java.io.IOException; import java.io.Serializable; import java.net.ServerSocket; import java.net.Socket; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.RejectedExecutionHandler; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantLock; public class Server { private static int produceTaskSleepTime = 100; private static int consumeTaskSleepTime = 1200; private static int produceTaskMaxNumber = 100; private static final int CORE_POOL_SIZE = 2; private static final int MAX_POOL_SIZE = 100; private static final int KEEPALIVE_TIME = 3; private static final int QUEUE_CAPACITY = (CORE_POOL_SIZE + MAX_POOL_SIZE) / 2; private static final TimeUnit TIME_UNIT = TimeUnit.SECONDS; private static final String HOST = "127.0.0.1"; private static final int PORT = 19527; private BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<Runnable>(QUEUE_CAPACITY); //private ThreadPoolExecutor serverThreadPool = null; private ExecutorService pool = null; private RejectedExecutionHandler rejectedExecutionHandler = new ThreadPoolExecutor.DiscardOldestPolicy(); private ServerSocket serverListenSocket = null; private int times = 5; public void start() { // You can also init thread pool in this way. /*serverThreadPool = new ThreadPoolExecutor(CORE_POOL_SIZE, MAX_POOL_SIZE, KEEPALIVE_TIME, TIME_UNIT, workQueue, rejectedExecutionHandler);*/ pool = Executors.newFixedThreadPool(10); try { serverListenSocket = new ServerSocket(PORT); serverListenSocket.setReuseAddress(true); System.out.println("I'm listening"); while (times-- > 0) { Socket socket = serverListenSocket.accept(); String welcomeString = "hello"; //serverThreadPool.execute(new ServiceThread(socket, welcomeString)); pool.execute(new ServiceThread(socket)); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } cleanup(); } public void cleanup() { if (null != serverListenSocket) { try { serverListenSocket.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } //serverThreadPool.shutdown(); pool.shutdown(); } public static void main(String args[]) { Server server = new Server(); server.start(); } } class ServiceThread implements Runnable, Serializable { private static final long serialVersionUID = 0; private Socket connectedSocket = null; private String helloString = null; private static int count = 0; private static ReentrantLock lock = new ReentrantLock(); ServiceThread(Socket socket) { connectedSocket = socket; } public void run() { increaseCount(); int curCount = getCount(); helloString = "hello, id = " + curCount + "\r\n"; ExecutorService executor = Executors.newSingleThreadExecutor(); Future<String> future = executor.submit(new TimeConsumingTask()); DataOutputStream dos = null; try { dos = new DataOutputStream(connectedSocket.getOutputStream()); dos.write(helloString.getBytes()); try { dos.write("let's do soemthing other.\r\n".getBytes()); String result = future.get(); dos.write(result.getBytes()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { if (null != connectedSocket) { try { connectedSocket.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if (null != dos) { try { dos.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } executor.shutdown(); } } private int getCount() { int ret = 0; try { lock.lock(); ret = count; } finally { lock.unlock(); } return ret; } private void increaseCount() { try { lock.lock(); ++count; } finally { lock.unlock(); } } } class TimeConsumingTask implements Callable<String> { public String call() throws Exception { System.out.println("It's a time-consuming task, you'd better retrieve your result in the furture"); return "ok, here's the result: It takes me lots of time to produce this result"; } } |
运行程序
运行服务端,客户端只需使用telnet 127.0.0.1 19527 即可看到信息如下:
发表评论
-
web开发框架——JSF开发实战
2006-01-23 20:01 1408JSF开发实战的第一篇(jsf开发实战一)演示了如何建立一个最 ... -
Tomcat 的数据库连接池设置与应用
2006-01-23 20:28 7601.将数据库驱动程序的JAR文件放在Tomcat的 commo ... -
Eclipse Plugins Manager Beta 0.1 (Link's Only) 发布
2006-03-18 17:11 780<noscript type="text/ja ... -
常青图书管理系统 BETA V0.1
2006-03-19 15:03 833<noscript type="text/ja ... -
Java程序的性能优化
2006-03-19 15:15 798<noscript type="text/ja ... -
Java中四种XML解析技术之不完全测试
2006-03-20 12:16 691<noscript type="text/ja ... -
解决Tomcat中文乱码问题
2006-03-26 22:58 858一、中文问题的来源 计算机最初的操作系统支持的编码是单 ... -
Swing技巧. 设置全局字体(sun jdk)
2006-04-02 14:04 1330S ... -
Dom4j 使用简介
2006-04-05 20:19 666DOM4J是dom4j.org出品的一个开源XML解析包 ... -
Java手机技术 之 J2ME及其基本慨念
2006-04-06 12:42 719如果您曾经http://www.javasoft.com ;网 ... -
Java手机技术 之 J2ME新手入门要点
2006-04-06 12:50 997一、J2ME中需要的Java基础知识现在有大部分人,都是从零开 ... -
JAVA设计模式系列之Singleton模式
2006-04-06 13:18 820单态定义: Singleton模式主要作用是保证在Java应 ... -
高手指点你实战体会Java的多线程编程
2006-04-06 13:39 831在 Java 程序中使用多线程要比在 C 或 C++ 中容 ... -
Java基础--JSP应用语法详解大全
2006-04-06 13:49 8891)HTML注释: 可以用注释内容,也可以用表达式. 2) ... -
javamail使用完全手册
2006-04-08 20:44 8671,哪里是开始:初始环境,安装好你的j2sdk和你的web服务 ... -
JavaMail通过sina的smtp验证
2006-04-08 20:47 1109import javax.mail.*;import java ... -
用javamail发送邮件
2006-04-08 20:49 989用javamail发送邮件 aistill(原作) ... -
修改后可以发送附件、抄送、密送的javabean
2006-04-08 20:51 924/**A ... -
javamail实现smtp身份认证
2006-04-08 20:57 941现在大多 ... -
TOMCAT 5设置数据连接池总结
2006-04-14 21:34 494TOMCAT 5,要设置一个数据连接池,以MYSQL为例子(M ...
相关推荐
本文将结合Java 5.0中的新特性,讲解如何在Java中实现多线程编程实践。 在Java 5.0之前,多线程的实现主要依赖于`java.lang.Thread`类和`synchronized`关键字。尽管这些机制能够满足基本的多线程编程需求,但在复杂...
### Java 5.0 多线程编程实践 在Java 5.0版本中,多线程编程得到了显著增强,特别是在引入了`java.util.concurrent`包之后,为开发者提供了更为丰富的API来处理并发问题。本篇文章将深入探讨如何在Java 5.0中有效地...
8. **多线程(Multithreading)**:Java API提供了Thread类和Runnable接口来支持多线程编程,理解和掌握线程的同步、互斥、线程池等概念对于开发高并发应用程序至关重要。 9. **I/O流(Input/Output Streams)**:...
Java 5.0对并发编程进行了大量优化,包括新增了java.util.concurrent包,提供了线程池、并发容器(如ConcurrentHashMap)以及Future和Callable接口,使得多线程编程更加高效和易于管理。 通过深入学习和实践《Java ...
除此之外,书中还可能涉及了Java 5.0中的多线程和并发编程,包括新的并发API如`java.util.concurrent`包,以及线程池、Future和Callable接口等概念。这些内容对于构建高性能、高并发的Web应用至关重要。 总的来说,...
9. **并发工具**:Java 5.0引入了`java.util.concurrent`包,提供了线程池、并发容器、同步工具类等,帮助开发者更好地管理多线程和并发编程。 10. **定时器和定时任务**:`java.util.Timer`和`java.util.TimerTask...
10. **Concurrency Updates(并发更新)**:Java 5.0增强了多线程编程的支持,如引入了`java.util.concurrent`包,包含Semaphore、ExecutorService、Future、Callable等类,提供了更高效的线程管理和任务调度。...
总之,“Java多线程编程实战指南+设计模式篇(全部)”是一份宝贵的资源,它将帮助读者深入理解Java多线程编程的各个方面,以及如何利用设计模式解决实际问题。学习并掌握这些知识,对于提升Java程序员的专业技能和...
《Java 5.0 Tiger》是一本针对Java编程语言5.0版本的权威指南,尤其对Tiger(Java 5.0的代号)引入的新特性进行了深入的讲解。这本书的源码是学习和理解Java 5.0新特性的宝贵资源,包括泛型、枚举、自动装箱与拆箱、...
在并发处理方面,Java 5.0引入了并发工具类(java.util.concurrent),如ExecutorService、Future、Semaphore等,这些工具简化了多线程编程,提高了程序的可维护性和性能。还有改进的synchronized关键字,支持基于...
这个"Java5.0 Tiger全书代码.rar"压缩包包含的是《Java5.0 Tiger程序员高手秘笈》这本书的配套源码,这是一本深受Java开发者喜爱的进阶指南,旨在帮助读者深入理解Java 5.0的新特性和最佳实践。 首先,Java 5.0的...
Java 5.0认证指南不仅涵盖了Java语言的基础知识,还深入探讨了高级主题,如面向对象设计原则、多线程编程、网络编程等。对于希望获得SCJP或SCJD认证的开发者来说,这是一份不可或缺的学习资源。通过系统地学习和实践...
10. **练习题的扩展**:书中包含了大量练习题,总数达到了670道,涵盖了强化训练、创新思维以及项目实践等多个层面,新增加的练习题包括维护游戏高分列表、评估后缀表达式和中缀表达式、最小最大值游戏树评估等。...
除了上述核心概念和工具类,Java 5.0引入了并发工具类如CountDownLatch、CyclicBarrier、Semaphore等,它们为多线程编程提供了更细致的控制。比如,CountDownLatch允许一个或多个线程等待其他线程完成操作,...
13. **线程并发库**:Java 5.0引入了java.util.concurrent包,包含各种并发工具类,如ExecutorService、Future、Semaphore等,使得多线程编程更加高效和安全。 14. **枚举类的枚举常量间的关系**:书中可能还会讨论...
10. **并发编程改进**:Java 5.0引入了`java.util.concurrent`包,包含了线程池、Future、Callable、BlockingQueue等并发工具,提升了多线程环境下的编程效率和安全性。 这些是Java JDK 5.0的主要特性,它们不仅...
Java多线程与锁是Java并发编程中的核心概念,它们在构建高效、可扩展的并发应用程序中起着至关重要的作用。下面将详细讲解这两个主题。 首先,Java中的多线程是指程序执行时可以同时进行多个任务。这得益于操作系统...