Java中输入流的read()为阻塞式方法的相关实例

说来惭愧,本人学习Android已经半年有余,然收效甚微。也许想要保持学习的激情,不断有所进益,真得时常做些总结。
所以我决定通过写博文记录自己的学习状态,分享学习成果,总结一路上的坎坷辛苦。我想这样的反馈,是一种警示,也是一种鼓励。也将自己遇到的问题做一个系统性的解答和整理。

最近在写一个通信相关的线程。Android客户端通过TCP/IP协议与下位机进行通信。要求下位机每发送一个信号,客户端要将其接收并显示出来,数据发送的频率很慢,大概是1byte/s 。也就是说数据流中大部分时间都是空的。
通信线程很简单代码如下:

class connectThread extends Thread
    {
        public void run()
        {
            // 当线程执行完run()函数时结束
            // 线程抛出一个未能捕获到的exception或error
            try
            {
                InetAddress serverAddr = InetAddress.getByName(IP);
                socket = new Socket(serverAddr, port);
                Input = socket.getInputStream();
                if (socket != null)
                {
                    int temp = 0;

                    byte[] data = new byte[1];
                    int c=0;
                    Log.e("Thread","44444444"+"---->"+temp);
                    while (temp != -1)
                    {
                        Log.e("Thread","---->"+(c++));
                        temp = Input.read(data);
                        Log.e("Thread","5555555"+"---->"+temp);

                        String line = new String(data, 0, temp);
                        int a = Integer.parseInt(line);
                        Log.e("Thread", a+"");
                        Message message = new Message();
                        message.arg1 = a;
                        mHandler.sendMessage(message);
                        Log.e("Thread","6666666"+"---->"+temp);
                    }
                }

            } 
            catch (Exception e)
            {
            }
        }
    }

很好,线程的运行结果很正常。完美地达到了我的预期。日志输出周期与下位机数据发送保持了高度一致。
Java中输入流的read()为阻塞式方法的相关实例_第1张图片

那么问题来了!它是怎么做到的。换句话说:为什么数据发送与while循环的频率能够保持一致?
没有弄明白这其中的关卡实在让我坐立难安,运行成功也没啥成就感。
最开始我陷入了这样一个怪圈。temp用于获取data的长度,也就是说一旦数据流中有数据,就会被数据流对象input的read()方法读入到data数组中,并且将数组的长度反映给temp。而while循环的判断条件是(temp != -1),这是一个只要网络连接没有断开就可以成立的条件,那么理论上while循环就会一只继续,势必会出现temp为0的情况,产生一个没有读取到任何数据的无效周期。因为我在前面说过这个下位机发送数据的周期大约在1byte/s, 这是一个远大于while循环耗时的周期啊!

那么,究竟是为什么呢?为什么呢为什么呢?为什么每个周期都跑得好好地,及时乖乖响应下位机的指令呢?

说到这里就是关键之处了,不得不给自己的Java基础捏把汗。InputStream是输入流,它的read()究竟是如何工作的呢?原来这个方法是一个阻塞式的方法,也就是死皮赖脸型的。我向你要数据,你说什么?没有!没有我就不走了,我就在这等着,其他人也给我一边候着,只有等我要到了东西才有你们说话的份。 所以每当程序运行至temp = Input.read(data); 都会等待,直到InputStream中有数据为止,它就会马上据为己有。真是个心机婊。

以上线程的运行机制就解释清楚了,不过由于read方法的等待过程很长占用了大量的资源。后来觉得这并不是一种很好的方法,解决这个问题更适合采用监听机制,监听到数据流中有数据之后再开启线程,执行完毕后关闭数据接收线程。这样就不会影响其它机制的工作。

你可能感兴趣的:(Android,Java)