Java-readLine()阻塞问题及解决过程

 更新时间:2026年05月07日 08:30:36   作者:昫 灬  
文章主要讨论了socket编程中readLine()方法的阻塞问题,在使用readLine()接收消息时,如果没有换行符,则会一直阻塞,解决方法是在发送消息时添加换行符,或者为每个客户端创建独立的转发线程

socket编程中readLine()阻塞问题

readLine()的API说明

  • public String readLIne() throws IOException

中文版:

  • 读一行文字。 一行被视为由换行符(’\ n’),回车符(’\ r’)中的任何一个或随后的换行符终止。
  • 返回:包含行的内容的字符串,不包含任何行终止字符,如果到达流末尾,则为null

英文版:

  • Reads a line of text. A line is considered to be terminated by any one of a line feed (’\n’), a carriage return (’\r’), or a carriage return followed immediately by a linefeed.
  • Returns:
  • A String containing the contents of the line, not including any line-termination characters, or null if the end of the stream has been reached

遇到的问题:

  • 当使用socket写一个双向通信的服务端时,总是接收不到来自用户的消息,和书上比对才发现是readLine()的问题,
  • 还有就是客户端和服务端的初始状态问题(一个为初始为“发送”,一个为“接收”)

第一种情况

  • 一个客户端,一个服务端。当服务端使用readLine()读消息时,需要读到一个换行符(‘\n’,或’\r’)才会结束。否则回一直阻塞,主线程就挂在这儿了
  • 解决方法:在客户端发送消息的时候,外加一个换行符
//用户发送消息的线程
class SentMessage extends Thread{
        private Socket socket;
        private BufferedWriter bw;
        private BufferedReader mysc;
        SentMessage(Socket socket){
            this.socket = socket;
            try {
                bw = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
                mysc = new BufferedReader(new InputStreamReader(System.in));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        @Override
        public void run(){
            try{
                while (true){
                    String mymessage = mysc.readLine();
                    bw.write(mymessage+"\n");
                    bw.flush();
                    if("bye".equals(mymessage)){
                        break;
                    }
                }
            }catch (IOException e){
                e.printStackTrace();
            }finally {
                try{
                    if(mysc!=null){
                        mysc.close();
                    }
                    if(bw!=null){
                        bw.close();
                    }
                }catch (IOException e){
                    e.printStackTrace();
                }
            }
        }
    }

第二种

  • 当用服务器转发来自每个用户的消息到聊天室时,如果就用一个"转发消息"方法也会出现问题,就是使用了readLine()的阻塞
  • 思考:一个客户都应有一个自己”转发消息“通道(线程),不和其他客户共用一个”转发通道“(会导致阻塞
  • 解决,用一个线程来做转发
//内置线程类用于接收消息,并广播
    class AcceptMessage extends Thread{
        private Socket clientsocket;
        private BufferedReader br;
        AcceptMessage(Socket clientsocket){
            this.clientsocket = clientsocket;
        }
        /**
         * 服务器将所有接收的消息广播(显示在每一个客户的聊天窗口中
         * 注意:如果这里不用线程,会出现问题,思考---其实就是readLine()阻塞的问题
         */
        private void tellEveryone(Socket socket){
            try{
                //先从发送消息的客户读内容
                br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                String message = br.readLine();
                chatArea.append("用户"+socket.getPort()+": "+message+"\n");
                //然后将内容广播到每一个客户接口
                Iterator<Socket> it = list.iterator();
                while (it.hasNext()){
                    Socket socket2 = it.next();
                    //对自己就不要广播了
                    if(socket!=socket2){
                        bw = new BufferedWriter(new OutputStreamWriter(socket2.getOutputStream()));
                        bw.write(socket2.getInetAddress().getHostAddress()+": "+message+"\n");
                        bw.flush();
                    }
                }
            }catch (IOException e){
                e.printStackTrace();
            }
        }
        @Override
        public void run(){
            while (true){
                //接收并广播
                tellEveryone(clientsocket);
            }
        }
    }

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Java @Mapper 使用注解的方式注入SQL的详细过程

    Java @Mapper 使用注解的方式注入SQL的详细过程

    文章主要介绍了MySQL的JSON数据类型及其使用方法,包括在表中存储和处理JSON数据、使用JSON数据进行复杂查询以及在SQL语句中处理JSON数据的示例,感兴趣的朋友跟随小编一起看看吧
    2025-12-12
  • Java Spring分别实现定时任务方法

    Java Spring分别实现定时任务方法

    这篇文章主要为大家详细介绍了Java与Spring设置动态定时任务的方法,定时任务的应用场景十分广泛,如定时清理文件、定时生成报表、定时数据同步备份等
    2022-07-07
  • JavaMap两种遍历方式keySet与entrySet详解

    JavaMap两种遍历方式keySet与entrySet详解

    这篇文章主要介绍了JavaMap两种遍历方式keySet与entrySet,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习吧
    2023-03-03
  • AsyncHttpClient exception异常源码流程解析

    AsyncHttpClient exception异常源码流程解析

    这篇文章主要为大家介绍了AsyncHttpClient的exception源码流程解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-12-12
  • Java中的@RequiredArgsConstructor注解详解

    Java中的@RequiredArgsConstructor注解详解

    这篇文章主要介绍了Java中的@RequiredArgsConstructor注解详解,@RequiredArgsConstructor是Lombok的一个注解,简化了我们对@Autowired书写,@RequiredArgsConstructor注解可以代替@Autowired注解,需要的朋友可以参考下
    2024-01-01
  • Spring IOC源码之bean的注册过程讲解

    Spring IOC源码之bean的注册过程讲解

    这篇文章主要介绍了Spring IOC源码之bean的注册过程讲解,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-09-09
  • Spring Boot 整合持久层之Spring Data JPA

    Spring Boot 整合持久层之Spring Data JPA

    在介绍Spring Data JPA的时候,我们首先认识下Hibernate。Hibernate是数据访问解决技术的绝对霸主,使用O/R映射技术实现数据访问,O/R映射即将领域模型类和数据库的表进行映射,通过程序操作对象而实现表数据操作的能力,让数据访问操作无须关注数据库相关的技术
    2022-08-08
  • Java轻松使用工具类实现获取wav时间长度

    Java轻松使用工具类实现获取wav时间长度

    在Java中,工具类定义了一组公共方法,这篇文章将介绍Java中使用工具类来获取一个wav文件的时间长度,感兴趣的同学继续往下阅读吧
    2021-10-10
  • IDEA如何让控制台自动换行

    IDEA如何让控制台自动换行

    本文介绍了如何在IDEA中设置控制台自动换行,具体步骤为:File -> Settings -> Editor -> General -> Console,然后勾选"Use soft wraps in console"选项
    2025-01-01
  • SpringBoot整合PowerJob实现定时任务调度

    SpringBoot整合PowerJob实现定时任务调度

    最近项目需要使用定时任务,而使用了PowerJob做任务调度模块,感觉这个框架真香,今天我们就来深入了解一下新一代的定时任务框架——PowerJob,需要的朋友可以参考下
    2024-03-03

最新评论