线程池
每一个线程的启动和结束都是比较消耗时间和占用资源的。
如果在系统中用到了很多的线程,大量的启动和结束动作会导致系统的性能变卡,响应变慢。
为了解决这个问题,引入线程池这种设计思想。
线程池的模式很像生产者消费者模式,消费的对象是一个一个的能够运行的任务
设计思路
线程池的思路和生产者消费者模型是很接近的。
- 准备一个任务容器
- 一次性启动10个 消费者线程
- 刚开始任务容器是空的,所以线程都wait在上面。
- 直到一个外部线程往这个任务容器中扔了一个“任务”,就会有一个消费者线程被唤醒notify
- 这个消费者线程取出“任务”,并且执行这个任务,执行完毕后,继续等待下一次任务的到来。
- 如果短时间内,有较多的任务加入,那么就会有多个线程被唤醒,去执行这些任务。
在整个过程中,都不需要创建新的线程,而是循环使用这些已经存在的线程。
使用JAVA自带的线程池
创建一个线程池类ThreadPoolExecutor有两种方式,
第一种是用Executors,
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
private ThreadPoolExecutor executor;//java自带的线程池类;
public Server(){//创建线程池;
//executor=(ThreadPoolExecutor)Executors.newCachedThreadPool();//不带参数,线程池个数无限
executor=(ThreadPoolExecutor)Executors.newFixedThreadPool(5);//带参数线程池个数有限;
}
这种方式创建线程池不推荐,因为会有运行风险,线程个数可能不受控制,下面来介绍第二种
第二种是用ThreadPoolExecutor;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
ThreadPoolExecutor threadPool= new ThreadPoolExecutor(10, 15, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
第一个参数10 表示这个线程池初始化了10个线程在里面工作
第二个参数15 表示如果10个线程不够用了,就会自动增加到最多15个线程
第三个参数60 结合第四个参数TimeUnit.SECONDS,表示经过60秒,多出来的线程还没有接到活儿,就会回收,最后保持池子里就10个
第四个参数TimeUnit.SECONDS 如上
第五个参数 new LinkedBlockingQueue() 用来放任务的集合
这个方法创建线程池可以使创建的参数更容易理解,还降低程序运行出错的风险,极力推荐,下面放一段代码,是客户端和服务端的例子
线程池类:
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class Server {
ThreadPoolExecutor threadPool= new ThreadPoolExecutor(10, 15, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
public void submitTask( Worker worker){
threadPool.execute(worker);
}
}
任务类:
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;
public class Worker implements Runnable{
Socket s;
public Worker(Socket s) {
this.s = s;
}
public void run() {
try {
System.out.println("服务人员已经启动");
InputStream ips = s.getInputStream();
OutputStream ops = s.getOutputStream();
DataInputStream br=new DataInputStream(ips);
DataOutputStream dos = new DataOutputStream(ops);
Scanner sc=new Scanner(System.in);
while (true) {
String strWord = br.readUTF();
System.out.println("client said:" + strWord );
if (strWord.equalsIgnoreCase("quit"))
break;
String str=sc.next();
System.out.println("server said:" + str );
dos.writeUTF(str + System.getProperty("line.separator"));
}
br.close();
// 关闭包装类,会自动关闭包装类中所包装的底层类。所以不用调用ips.close()
dos.close();
s.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
服务端:
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class TcpServer {
public static void main(String[] args) {
// 创建一个执行服务器
Server server=new Server();
try {
ServerSocket ss=new ServerSocket(8008);
while(true)
{
Socket s=ss.accept();
System.out.println("来了一个client");
Worker worker =new Worker(s);
server.submitTask(worker);//向线程池提交任务;
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
客户端:
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
public class TcpClient {
public static void main(String[] args) {
try {
Socket s=new Socket(InetAddress.getByName("192.168.1.10"), 8008);
InputStream ss=s.getInputStream();
DataInputStream ios=new DataInputStream(ss);
OutputStream dop =s.getOutputStream();
DataOutputStream dos=new DataOutputStream(dop);
Scanner sc=new Scanner(System.in);
while(true)
{
String str=sc.next();
if(str.equalsIgnoreCase("quit"))
{
break;
}
else
{
System.out.println("向客户端发出:"+str);
dos.writeUTF(str+ System.getProperty("line.separator"));
String dr=ios.readUTF();
System.out.println("收到服务端消息:"+dr);
}
}
s.close();
ss.close();
dop.close();
sc.close();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}