BIO模型分析

伪代码

class Server {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPollExecutor(100);
        serverSocket.bind(9090);
        //主线程等待新连接的到来
        while (!Thread.currentThread.isInturrupted()) {
            Socket socket = serverSocket.accpet();
            //将新的连接交给线程池处理
            executor.submit(new ConnectIOHandler(socket));
        }
    }
}

class ConnectIOHandler implements Runnable {
    private Socket socket;

    public ConnectIOHandler(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        while (!Thread.currentThread.isInturruted()) {
            //读取数据
            String data = socket.read()....
            if (data != null) {
                //处理数据
                dosomething();
                //写数据
                socket.write()...
            }
        }
    }

}

    上述模型的一些特性:

1. 每连接每线程。socket.accept()、socket.read()、socket.write()这三个函数均是同步阻塞,当一个连接在处理I/O时,系统是阻塞的,如果是单线程的话必然会挂死。开启多线程,会将CPU释放出来,可以处理更多的事情。

2. 使用线程池,降低线程创建和回收的成本。

    缺点就是严重依赖线程:

1. 线程的创建和销毁的成本很高,在Linux中,线程本质就是一个进程(科普:Linux里面的线程其实是通过fork函数来fork一个子进程的方式来实现的,并且是通过关闭COW(Copy on Write)特性来实现线程间独立但是又共享父进程内存的效果。总而言之,在Linux世界里,线程其实就是进程,进程是Linux内核调度的实体。),创建和销毁都是重量级的系统函数。

2. 线程本身占用较大内存,像Java的线程栈,一般至少分配512K~1M的空间(不显式设置-Xss或-XX:ThreadStackSize时,在Linux x64上ThreadStackSize的默认值就是1024KB,给Java线程创建栈会用这个参数指定的大小。),并发高时,JVM的内存会吃紧。

3. 线程的切换成本高,操作系统线程切换时,需要保留线程的上下文,然后进行系统调用。高并发时,可能会导致线程切换的时间大于线程执行的时间,带来系统load偏高,CPU sy使用率特别高,导致系统陷入几乎不可用状态。

4. 容易造成锯齿状的系统负载。因为系统负载是用活动线程数或CPU核心数,一旦线程数量高但外部网络环境不是很稳定,就很容易造成大量请求的结果同时返回,激活大量阻塞线程从而使系统负载压力过大。

 

转载于:https://my.oschina.net/vbird/blog/1499045

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值