【Java知识点整理】 初识线程和BIO模式

学习时间 0722

什么是BIO模式?

知识点参考 本文转发自技术世界原文链接 http://www.jasongj.com/java/nio_reactor/

1、同步 vs. 异步
  • 同步I/O 每个请求必须逐个地被处理,一个请求的处理会导致整个流程的暂时等待,这些事件无法并发地执行。

    • 用户线程发起I/O请求后需要等待或者轮询内核I/O操作完成后才能继续执行。
  • 异步I/O 多个请求可以并发地执行,一个请求或者任务的执行不会导致整个流程的暂时等待。

    • 用户线程发起I/O请求后仍然继续执行,当内核I/O操作完成后会通知用户线程,或者调用用户线程注册的回调函数。
2、阻塞 vs. 非阻塞
  • 阻塞 某个请求发出后,由于该请求操作需要的条件不满足,请求操作一直阻塞,不会返回,直到条件满足。

  • 非阻塞 请求发出后,若该请求需要的条件不满足,则立即返回一个标志信息告知条件不满足,而不会一直等待。一般需要通过循环判断请求条件是否满足来获取请求结果。

目前学习的JavaIO就是属于阻塞式IO 即 BIO

3、BIO模式
  • Java IO的各种流是阻塞的。当某个线程调用read()或write()方法时,该线程被阻塞,直到有数据被读取到或者数据完全写入。阻塞期间该线程无法处理任何其它事情。

如上文所述,阻塞I/O下请求无法立即完成则保持阻塞。阻塞I/O分为如下两个阶段。

  • 阶段1:等待数据就绪。网络 I/O 的情况就是等待远端数据陆续抵达;磁盘I/O的情况就是等待磁盘数据从磁盘上读取到内核态内存中。
  • 阶段2:数据拷贝。出于系统安全,用户态的程序没有权限直接读取内核态内存,因此内核负责把内核态内存中的数据拷贝一份到用户态内存中。

线程

一、概念

  • 操作系统:windows
    • 操作系统下有很多进程
    • 进程的切换:时间消耗较多 <————> 线程的切换 较快
  • 进程:指正在进行运行的程序 (Process类
    • 应用程序 : 特指有界面的进程
      • 平常在java中运行main方法,这就是一个进程
    • 特点
      • 自己独立的内存空间
      • 一个时间只能做一件事情
    • 每个进程都会独立占用内存,并且里面会占用若干个线程
      • 每个进程肯定有一个主线程
      • 在资源管理器可以查看每个进程占用的线程
  • 线程——>?
1、什么是线程(Thread类)
  • 需要共享进程的内存 (简单理解:儿子需要用爸爸的钱

二、Thread类

  • 如何获取主线程?

    Thread thread = Thread.currentThread();
    System.out.println("当前的线程是:"+thread.getName());
    
  • 如何创建线程?

    1. 创建一个线程类,并且继承Thread类

    2. 重写 run()方法

      里面的内容,就是 这个线程要做的事情:实现的功能!

    3. 创建一个该类的实例化对象

    4. 执行该对象

  • Thread类的run()和start()的区别

    • run方法并没有开启新线程,实际情况:按照顺序执行,当对应的线程执行完毕后才会执行其他
    • start方法才能真正开启新线程,让两个线程交叉运行
  • 交叉运行和同时运行的区别

    • CPU一次执行执行一个进程,但是
    • 因为CPU的主频很高,比如2.4GHz = 2.4 * 1024 * 1024 * 1024 次/秒
      • 表示一秒钟可以运行的次数
    • CPU运行的速度很快,所以看起来像同时运行
  • 举个例子

    public class ThreadDemo extends Thread{
        @Override
        public void run() {
    //        super.run();
            System.out.println("当前线程是"+Thread.currentThread().getName());
            for (int i = 0; i < 10; i++) {
                System.out.println("线程的结果"+i);
                try {
                    // 使用Thread.sleep()方法,可以让线程休眠指定的一段时间(毫秒)
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    class Test {
        public static void main(String[] args) {
            // 主线程
            System.out.println("当前线程是"+Thread.currentThread().getName());
            // 开启了一个线程  ——> 创建一个线程的实例化对象
            ThreadDemo threadDemo = new ThreadDemo();
            // 注意 :启动线程是启动start()方法
    //        threadDemo.start();
            // 如果使用run() , 没有开启线程,会按照顺序执行,当run的线程执行完毕后才会执行其他线程
            threadDemo.run();
    
            // 让两个线程都执行同样的内容,可以发现两个线程都是同时运行的
            for (int i = 0; i < 10; i++) {
                System.out.println("main方法的结果"+i);
                try {
                    // 使用Thread.sleep()方法,可以让线程休眠指定的一段时间(毫秒)
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    

三、线程结合BIO模式

1、一对多,接受多人信息
  1. 创建一个新的线程类,构造函数传入Socket对象
  2. 在线程类里,重写run方法内 :加入 **对Socket的对象的操作(**如获取信息,输出信息
  3. 在主方法内,先开启端口服务
  4. while循环内,只要建立新的连接,就实例化一个线程对象,并执行run方法
2、多对多,实现多人群聊
  1. 建立一个全局的静态变量 ArrayList<Socket>
  2. 在创建新的Socket对象时,将这个对象进这个列表里
    • 简单理解:每个连接的用户都会有一个Socket对象,存列表内后续可以遍历
  3. 在线程内,输出信息时,先遍历列表,再输出每个Socket对象内存放的信息
  4. 注意:在使用输出流,先判断这个Socket是否关闭

举个例子

public class ServerThread extends Thread {
    private Socket socket;

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

    @Override
    public void run() {
        try {
            while (true) {
                // 获取 快速转换:原始的字节流——字符流——封装流
                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                String lineStr =  bufferedReader.readLine();
                System.out.println("接收到的数据为:" + lineStr);

                System.out.println("====实现群聊功能(转发其他用户的消息 ) 列表长度" + ServerChat.socketList.size());
                // 遍历列表获取Socket对象
                for (Socket otherSocket : ServerChat.socketList) {
                    // 如果没有关闭 在执行后续操作
                    if (!otherSocket.isClosed()) {
                        // 发送输出流
                        PrintWriter printWriter = new PrintWriter(new OutputStreamWriter(otherSocket.getOutputStream()));
                        printWriter.println(lineStr);
                        printWriter.flush();
                    }
                }
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Xcong_Zhu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值