系统启动一个新线程的成本是比较高的,因为它涉及与操作系统交互。在这种情形下,使用线程池可以很好的提高性能,尤其是当程序需要创建大量生存周期很短的线程时,更应该考虑使用线程池。
与数据库连接池类似的是,线程池在系统启动的时候创建大量空闲的线程,程序将一个Runnable对象传给线程池,线程池就会启动一条线程来执行该对象的run方法,当run方法执行结束后,该线程并不会死亡,而是再次返回线程池中成为空闲状态,等待下一个Runnable对象的run方法。
除此之外,使用线程池可以有效控制系统中并发线程的数量,但系统中包含大量并发线程时,会导致系统性能急剧下降,而线程池的最大线程数量可以控制系统中并发线程的数目不超过此数目。 在jdk1.5以前,开发者必须手动实现自己的线程池,从jdk1.5开始,java内建支持线程池。
相关类介绍:
1. java.util.concurrent.Executors:此类是一个工厂类,提供了生成线程池的方法,主要提供了以下几个静态方法来生成各种线程池。
l newCachedThreadPool():创建一个具有缓存功能的线程池,系统根据需要创建线程,这些线程将被缓存。
l newFixedThreadPool(int nThreads);创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程,在需要时使用提供的 ThreadFactory 创建新线程。
l newSingleThreadExecutor();创建只有一个单线程的线程池,相当于newFixedThreadPool()传入的参数为1.
l newScheduledThreadPool();创建一个线程池,它可安排在给定延迟后运行命令或者定期地执行。
前面三个方法都返回ExecutorService对象,该对象代表一个线程池,它可以执行Runnable对象或者Callable对象所代表的线程。而最后一个方法返回一个ScheduledExecutorService线程池,它是ExecutorService的子类,它可以在指定延迟后执行线程任务。
2. java.util.concurrent.ExecutorService: ExecutorService代表尽快执行线程池中的线程(只要线程池中有空闲的线程立即执行线程任务),程序只要将一个Runable对象或Callable对象提交给该线程池即可,该线程会尽快执行该任务。此类提供了三个方法:
l <T> Future<T>submit(Callable<T> task) :提交一个返回值的任务用于执行,返回一个表示任务的未决结果的 Future。
l Future<?> submit(Runnable task) :提交一个 Runnable 任务用于执行,并返回一个表示该任务的 Future。
l <T> Future<T> submit(Runnable task, T result) :提交一个 Runnable 任务用于执行,并返回一个表示该任务的 Future。
3. java.util.concurrent.ScheduledExecutorService:此类代表可在指定延迟或周期行执行线程任务的线程池,它提供了如下四个方法:
l <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) :创建并执行在给定延迟后启用的 ScheduledFuture。
l ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) : 创建并执行在给定延迟后启用的一次性操作。
l ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) :创建并执行一个在给定初始延迟后首次启用的定期操作,后续操作具有给定的周期;也就是将在 initialDelay 后开始执行,然后在 initialDelay+period 后执行,接着在 initialDelay + 2 * period 后执行,依此类推。
l ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) :创建并执行一个在给定初始延迟后首次启用的定期操作,随后,在每一次执行终止和下一次执行开始之间都存在给定的延迟。
当线程池用完以后,应该调用该线程池的shutdown方法,该方法将关闭线程池,调用了shurdown后的线程池将不再接受新的任务,但将会以前所有已经提交的任务执行完成。当线程池中所有的任务都执行完成后,线程池中的所有线程都会死亡;另外也可以调用线程池的shutdownNow方法来关闭线程池,该方法试图停止所有正在执行的活动任务。
使用线程池的步骤如下:
1. 调用Executors类的静态工厂方法创建一个ExecutorService对象,该对象代表一个线程池。
2. 创建Runable实现类或Callable实现类的实例,作为线程执行任务。
3. 调用ExecutorService对象的submit方法来提交Runnable或Callable实例。
4. 当不想提交任何任务时调用shutdown方法来关闭线程池。
下面是一个简单的例子,客户端发送消息,服务器端接受消息,并输出。
Server:
package com.hs.threadpool;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @author jianggy
*
*/public class Server {
private int port=21245;
private ServerSocket ss;
public Server()
throws IOException{
ss =
new ServerSocket(port);
System.out.println("服务器启动。。。");
}
public void serverService(){
ExecutorService es = Executors.newFixedThreadPool(5);
while(
true){
Socket socket =
null;
try {
socket = ss.accept();
es.execute(
new ServerHandler(socket));
}
catch (Exception e) {
e.printStackTrace();
}
}
}
public static void main(String[] args)
throws IOException{
Server server =
new Server();
server.serverService();
}
}
package com.hs.threadpool;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Socket;
public class ServerHandler
implements Runnable {
private Socket socket;
private InputStream in;
public ServerHandler(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
char[] chars =
new char[100];
StringBuffer sb =
new StringBuffer();
try {
in = socket.getInputStream();
InputStreamReader reader =
new InputStreamReader(in);
while(reader.read(chars)!=-1){
sb.append(chars);
}
System.out.println(sb.toString());
}
catch (IOException e) {
e.printStackTrace();
}
}
}
Client:
package com.hs.threadpool;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
public class Client {
private static int port = 21245;
private static String ip = "192.168.231.166";
private SocketChannel sc;
private ByteBuffer bb = ByteBuffer.allocate(1024);
public void connectToServer()
throws IOException {
try {
sc = SocketChannel.open();
InetSocketAddress add =
new InetSocketAddress(ip,port);
sc.connect(add);
while(!sc.finishConnect()){
System.out.println("waitting connect to server。。。。。。");
Thread.sleep(100);
}
Thread.sleep(10000);
bb = ByteBuffer.wrap("abcdefg".getBytes());
sc.write(bb);
bb.clear();
}
catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally{
if(sc!=
null&&sc.isConnected()){
sc.close();
System.out.println("connetion is closed
.");
}
}
}
public static void main(String[] args)
throws IOException{
Client c =
new Client();
c.connectToServer();
}
}
-----------------------------------------------------
Silence, the way to avoid many problems;
Smile, the way to solve many problems;