java I/O 学习笔记2 ,线程池

线程池:就是为了解决一客户端一线程的过度资源消耗问题,而在预先定义好线程的数量,而当有新的请求接入时,就将这个新的请求接入封装成一个task丢到线程池中处理,在这种情况下,资源的使用是可控的。

同样,以一个客户端发送消息,服务器接收并且返回消息的例子作为分析。

思路:
Server端:
1. server端使用ServerSocket的一个实例,绑定端口并且监听,
2. 创建一个线程池,指定线程池属性
3. ServerSocket实例将接收到的每个socket单独封装成一个task,
4. 将task丢到线程池中处理
Client端:
1. 新建一个Socket实例,并且连接到server,(建议将这个Socket封装成一个单独的类),
2. 获取Socket的输入流和输出流,收发信息

Server端代码:三部分组成,ExecutorPoolServer.java,主函数入口
;ExecutePoolServerHandler.java,用于封装线程池的类;BIOSocketHandler.java;负责到客户端的Soket连接;

代码:
ExecutePoolServer.java

package learningNote.IO;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class ExecutePoolServer {

    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        int port=8090;

        ServerSocket ss=new ServerSocket(port);

        ExecutePoolServerHandler esph=new ExecutePoolServerHandler();//创建线程池

        while(true){
            System.out.println(esph.activtedThreadCount());//查看这个线程池上面的活跃线程数
            Socket s=ss.accept();
            esph.execute(new BIOSocketHandler(s));//将新的请求连接放入线程池中
        }
    }

}

ExecutePoolServerHandler.java

package learningNote.IO;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class ExecutePoolServerHandler{

    private ExecutorService es;
    public ExecutePoolServerHandler() {
        // TODO Auto-generated constructor stub
        es=new ThreadPoolExecutor(1, 2, 1000, TimeUnit.MICROSECONDS, new ArrayBlockingQueue<Runnable>(10));//这个构造函数的说明可以查阅:https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ThreadPoolExecutor.html#ThreadPoolExecutor(int, int, long, java.util.concurrent.TimeUnit, java.util.concurrent.BlockingQueue)
    }

    public void execute(Runnable task){
        es.execute(task);//这里的参数必须是Runnable类型的实例,因为jvm创建的线程会根据此来调用run()方法
    }

    public int activtedThreadCount(){
        return Thread.activeCount();
    }
}

BIOSocketHandler.java

package learningNote.IO;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

public class BIOSocketHandler implements Runnable{

    private Socket s;

    public BIOSocketHandler(Socket s) {
        // TODO Auto-generated constructor stub
        this.s = s;
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub
        try (BufferedReader in=new BufferedReader(new InputStreamReader(s.getInputStream()));//获取socket的输入流
             PrintWriter out=new PrintWriter(s.getOutputStream(),true);//获取socket的输出流,并且设置自动刷新缓冲区
                ){
            //读取输入消息并打印
            String message=" ";

            while(true){
                //读取输入消息
                while(true){
                    String temp=in.readLine();
                    if(temp.equals("ok")){
                        break;
                    }
                    message+=temp+"\n";
                }
                //打印收到的消息
                System.out.print(message);

                //返回消息
                String now=new java.util.Date().toString(); 
                out.println(now+" "+message+"ok");
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            System.exit(1);
        }


    }

}
  1. 当线程池中的线程(指定的最大线程)已经全部用完之后,新的task会被放到ArrayBlockingQueue,这时一个顺序队列,属于先进先出的一种能够算法.,就是最先进入的元素也会最先出队。
  2. 注意到server 端socket会一直存在直到client端的socket被关闭,也就是说,会导致线程的一直占用
  3. 注意InputStream中的read方法,这个方法本身也会引起阻塞因为它不会立即被返回直到:数据可用(input data is available ,),数据读取完毕(end of the file is detected ),或者抛出错误(throw a exception)。..前两者的情况不太清楚…因为这样岂不是会被返回两次??
  4. OutputStream中的write方法,也会造成阻塞,(这很大程度上与tcp/ip缓冲区以及网络状况有关)..

    Client端代码:
    ExecutePoolClient .java

package learningNote.IO;

import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;

public class ExecutePoolClient {

    public static void main(String[] args) throws UnknownHostException, IOException {
        // TODO Auto-generated method stub
        Socket s=new Socket("127.0.0.1",8090);
        new Thread(new BIOClientHandler(s)).start();
    }

}

BIOClientHandler.java

package learningNote.IO;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

public class BIOClientHandler implements Runnable {

    private Socket s;
    public BIOClientHandler(Socket s) {
        // TODO Auto-generated constructor stub
        this.s=s;
    }
    @Override
    public void run() {
        // TODO Auto-generated method stub
        try(BufferedReader in=new BufferedReader(new InputStreamReader(s.getInputStream()));
            BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
            PrintWriter out=new PrintWriter(s.getOutputStream(),true)){

            while(true){
                //从控制台读取输入
                String message=" ";
                  while(true){
                      String temp=br.readLine();
                      if(temp.equals("ok"))break;
                      message+=temp+"\n";
                  }
                  //发送消息
                  out.println(message+"ok");
                  //读取消息
                  String body=" ";
                  while(true){
                      String temp=in.readLine();
                      if(temp.equals("ok"))break;
                      body+=temp+"\n";
                  }
                  System.out.print(body);
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }


}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值