范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

谈谈代码JavaIO业务代码优化之路Java开发实战

  版本
  日期
  备注
  1.0
  2019.4.27
  文章首发
  1.1
  2021.6.10
  修改标题:从一段代码谈起——浅谈JavaIO接口-> 谈谈代码:Java IO业务代码优化之路1.前言
  前阵子休息天日常在寻找项目里不好的代码,看到了这样的一段代码:    private Result sshSameExec(Session session, String cmd) {         if (log.isDebugEnabled()) {             log.debug("shell command: {}", cmd);         }         UserInfo ui = getUserInfo();         session.setUserInfo(ui);         int exitStatus = 0;         StringBuilder builder = new StringBuilder();         ChannelExec channel;         InputStream in;         InputStream err;         try {             session.connect(connectTimeout);             channel = (ChannelExec) session.openChannel("exec");             channel.setCommand(cmd);             in = channel.getInputStream();             err = channel.getErrStream();             channel.connect();         } catch (Exception e) {             throw new CloudRuntimeException(e);         }          try {             long lastRead = Long.MAX_VALUE;             byte[] tmp = new byte[1024];             while (true) {                 while (in.available() > 0 || err.available() > 0) {                     int i = 0;                     if (in.available() > 0) {                         i = in.read(tmp, 0, 1024);                     } else if (err.available() > 0) {                         i = err.read(tmp, 0, 1024);                     }                     if (i < 0) {                         break;                     }                     lastRead = System.currentTimeMillis();                     builder.append(new String(tmp, 0, i));                 }                 if (channel.isClosed()) {                     if (in.available() > 0) {                         continue;                     }                     exitStatus = channel.getExitStatus();                     break;                 }                 if (System.currentTimeMillis() - lastRead > exeTimeout) {                     break;                 }             }         } catch (IOException e) {             throw new CloudRuntimeException(e);         } finally {             channel.disconnect();             session.disconnect();         }          if (0 != exitStatus) {             return Result.createByError(ErrorData.builder()                     .errorCode(ResultCode.EXECUTE_SSH_FAIL.getCode())                     .detail(builder.toString())                     .title(ResultCode.EXECUTE_SSH_FAIL.toString())                     .build());         } else {             return Result.createBySuccess(builder.toString());         }     }
  简单解释一下这段代码——即通过ssh到一台机器上,然后执行一些命令.对命令输出的东西,开了一个循环,每一次读一定的位置,然后以字节流的形式读回来.
  这段代码有点丑,于是我闻到了学习的味道.
  首先是对两个Stream的消费,很显然,在多核环境下,我们同时也只能够消费其中一个Stream.其次,这代码太挫了,自己定义一个tmp,然后1024、1024这样的去取出来.
  在改良之前,我们先来回顾一下JavaIO的接口定义.2.JavaIO 接口知识回顾2.1 低级抽象接口:InputStream 和 OutputStream
  这里有同学可能问了,为啥叫它低抽象接口呢?因为它离底层太近了,计算机本来就是处理二进制的,而这两个接口正是用来处理二进制数据流的.
  先简单看一眼这两个接口:InputStream**  * This abstract class is the superclass of all classes representing  * an input stream of bytes.  *  * 

Applications that need to define a subclass of InputStream * must always provide a method that returns the next byte of input. * * @author Arthur van Hoff * @see java.io.BufferedInputStream * @see java.io.ByteArrayInputStream * @see java.io.DataInputStream * @see java.io.FilterInputStream * @see java.io.InputStream#read() * @see java.io.OutputStream * @see java.io.PushbackInputStream * @since JDK1.0 */ public abstract class InputStream implements Closeable {.....}OutputStream/** * This abstract class is the superclass of all classes representing * an output stream of bytes. An output stream accepts output bytes * and sends them to some sink. *

* Applications that need to define a subclass of * OutputStream must always provide at least a method * that writes one byte of output. * * @author Arthur van Hoff * @see java.io.BufferedOutputStream * @see java.io.ByteArrayOutputStream * @see java.io.DataOutputStream * @see java.io.FilterOutputStream * @see java.io.InputStream * @see java.io.OutputStream#write(int) * @since JDK1.0 */ public abstract class OutputStream implements Closeable, Flushable {...}   我们可以发现,它们都实现了Closeable的接口.因此大家在使用这些原生类时,要注意在结束时调用Close方法哦.   这两个接口的常用实现类有: - FileInputStream和FileOutputStreamDataInputStream和DataOutputStream ObjectInputStream和ObjectOutputStream2.2 高级抽象接口——Writer和Reader   为啥说它是高级抽象接口呢?我们先来看看它们的注释:Writer/** * Abstract class for writing to character streams. The only methods that a * subclass must implement are write(char[], int, int), flush(), and close(). * Most subclasses, however, will override some of the methods defined here in * order to provide higher efficiency, additional functionality, or both. * * @see Writer * @see BufferedWriter * @see CharArrayWriter * @see FilterWriter * @see OutputStreamWriter * @see FileWriter * @see PipedWriter * @see PrintWriter * @see StringWriter * @see Reader * * @author Mark Reinhold * @since JDK1.1 */ public abstract class Writer implements Appendable, Closeable, Flushable {Reader/** * Abstract class for reading character streams. The only methods that a * subclass must implement are read(char[], int, int) and close(). Most * subclasses, however, will override some of the methods defined here in order * to provide higher efficiency, additional functionality, or both. * * * @see BufferedReader * @see LineNumberReader * @see CharArrayReader * @see InputStreamReader * @see FileReader * @see FilterReader * @see PushbackReader * @see PipedReader * @see StringReader * @see Writer * * @author Mark Reinhold * @since JDK1.1 */ public abstract class Reader implements Readable, Closeable {   我们可以看到,这个抽象类是用来面向character的,也就是字符.字符的抽象等级必然比字节高,因为字符靠近上层,即人类.2.3 优化输入和输出——Buffered   如果我们直接使用上述实现类去打开一个文件(如FileWriter 、FileReader 、FileInputStream 、FileOutputStream ),对其对象调用read、write、readLine等,每个请求都是由基础OS直接处理的,这会使一个程序效率低得多——因为它们都会引发磁盘访问or网络请求等.   为了减少这种开销,Java 平台实现缓冲 I/O 流。缓冲输入流从被称为缓冲区(buffer)的存储器区域读出数据;仅当缓冲区是空时,本地输入 API 才被调用。同样,缓冲输出流,将数据写入到缓存区,只有当缓冲区已满才调用本机输出 API。   用于包装非缓存流的缓冲流类有4个:BufferedInputStream和BufferedOutputStream·用于创建字节缓冲字节流, BufferedReader和BufferedWriter`用于创建字符缓冲字节流.3. 着手优化   之前,我们提到了这段代码写得搓的地方:首先是对两个Stream的消费,很显然,在多核环境下,我们同时也只能够消费其中一个Stream.其次,这代码太挫了,自己定义一个tmp,然后1024、1024这样的去取出来.   故此,我们可以考虑对每个Stream都进行包装,支持用线程去消费,其次我们可以用高级抽象分接口去适配Byte,然后去装饰成Buffer.   接下来,我们来看一段ZStack里的工具类ShellUtils,为了节省篇幅,我们仅仅截出它在IDE里的Structure:   run方法的核心:   我们可以看到StreamConsumer这个类,我们来看一下它的代码: private static class StreamConsumer extends Thread { final InputStream in; final PrintWriter out; final boolean flush; StreamConsumer(InputStream in, PrintWriter out, boolean flushEveryWrite) { this.in = in; this.out = out; flush = flushEveryWrite; } @Override public void run() { BufferedReader br = null; try { br = new BufferedReader(new InputStreamReader(in)); String line; while ( (line = br.readLine()) != null) { out.println(line); if (flush) { out.flush(); } } } catch (Exception e) { logger.warn(e.getMessage(), e); } finally { try { if (br != null) { br.close(); } } catch (IOException e) { logger.warn(e.getMessage(), e); } } } }   这段代码已经达到了我们的理想状态:线程消费,高级抽象.3.1 使用Kotlin3.1.1 Kotlin IO   闲话不多说,先贴代码为敬:import java.io.InputStream import java.io.InputStreamReader class StreamGobbler(private val inputStream: InputStream, private var result: StringBuilder) : Runnable { override fun run() { InputStreamReader(inputStream).buffered().use { it.lines().forEach { r -> result.append(r) } } } }   还是一样熟悉的配方,我们逐行来解读:定义一个类,并且要求构造函数必须传入InputStream和一个StringBuilder.且实现了Runnable接口,这意味着它可以被线程消费.覆写run方法.我们可以看到InputStream被适配成了InputStreamReader,这意味着它可以输出字符流了,然后我们使用了Kotlin的接口将其装饰成了Buffer.读每一行buffer,并appned到result这个StringBuilder里去.读完就可以告辞了,close.(use会将其关闭)3.1.2 Kotlin Coroutine   先看一下上面的图,我们都知道内核态线程是由OS调度的,但当一个线程拿到时间片时,却调到了阻塞IO,那么只能等在那边,浪费时间.   而协程则可以解决这个问题,当一个Jobhang住的时候,可以去做别的事情,绕开阻塞.更好的利用时间片.   最后,我们来看一下成品代码: override fun sshExecWithCoroutine(session: Session, cmd: String): SimpleResult { val ui = InnerUserInfo() session.userInfo = ui val exitStatus: Int var channel = ChannelExec() val inputBuilder = StringBuilder() val errorBuilder = StringBuilder() try { session.connect(connectTimeout) channel = session.openChannel("exec") as ChannelExec channel.setCommand(cmd) channel.connect() val inputStream = StreamGobbler(channel.inputStream, inputBuilder) val errStream = StreamGobbler(channel.errStream, errorBuilder) val customJob = GlobalScope.launch { customStream(inputStream, errStream) } while (!customJob.isCompleted) { // wait job be done } exitStatus = channel.exitStatus } catch (e: IOException) { throw java.lang.RuntimeException(e) } finally { if (channel.isConnected) { channel.disconnect() } if (session.isConnected) { session.disconnect() } } return if (0 != exitStatus) { return SimpleResult.createByError(ErrorData.Builder() .errorCode(ResultCode.EXECUTE_SSH_FAIL.value) .detail(errorBuilder.toString()) .title(ResultCode.EXECUTE_SSH_FAIL.toString()) .build()) } else { SimpleResult.createBySuccess(inputBuilder.toString()) } } private suspend fun customStream(inputStream: StreamGobbler, errorStream: StreamGobbler) { val inputDeferred = GlobalScope.async { inputStream.run() } val errorDeferred = GlobalScope.async { errorStream.run() } inputDeferred.join() errorDeferred.join() }   作者:泊浮目   链接:https://juejin.cn/post/6971215096282513416


华纺股份智能绿色工厂项目一期试生产运行滨州日报滨州网讯近日,记者在总投资8。72亿元的华纺股份有限公司智能绿色工厂建设项目现场了解到,该项目2个主生产车间完成主体建设和设备基础设施制作,对一期设备进行了联调联试并对部分中国新能源汽车产业正在用成绩单说话虽然受到芯片紧缺和上游原材料价格上涨的影响,近期车市大盘走低,但新能源汽车市场表现依然强劲,成绩单依然亮眼。最新数据显示,今年前7个月,国内新能源汽车累计销量已超国内历年销量,渗透realme真我首款平板产品渲染图曝光,或定位中低端最近有一组据称是realmePad的渲染图被曝光,从图片上看,该平板电脑采用了10。4英寸的全面屏,并支持手写笔。此前,官方就曾陆续发布一些暗示信息,预计realme将会在年内持续京东方BOE独家供应荣耀Magic3Pro系列手机89度超曲屏昨日晚间,在荣耀Magic3系列旗舰新品发布会上,荣耀终端有限公司CEO赵明正式发布了全新旗舰手机荣耀Magic3系列。新品发布后,京东方BOE表示,荣耀Magic3系列手机搭载的屏幕性能摄影拉满iQOO8将走MIX4不同的道路?8月11日,小米给我们带来了不少惊喜。MIX4拥有CUP全面屏陶瓷工艺机身UWB一指连120W有线秒充等,小米平板5拥有25601600分辨率MIUIforPad手写笔键盘八扬声器腾讯字节知乎入局餐饮中石化易捷咖啡上线一键到车服务这里是每周末准时上线的大眼商机一周微刊最近有消息透露知乎悄悄杀入餐饮消费赛道,旗下咖啡产品正式上线。除了知乎,越来越多互联网公司在餐饮消费做起了布局,此外,本周餐饮界还有哪些大事件vivoNEX5即将上线,6000mAh电池120W快充4nm芯片,很强势近年来,整个手机行业的竞争是越来越激烈,都在相互模仿,相互超越。如今各大智能手机厂商为了提升自己的市场份额,能在行业内站稳脚跟,都绞尽脑汁,方法各式各样。有的开始研发电竞手机,有的七夕美妆小时达!京东到家与丝芙兰达成战略合作,全国门店将陆续上线七夕前夕,达达集团旗下京东到家与高端美妆零售商丝芙兰共同宣布达成战略合作,让美丽1小时送到家。根据双方战略合作协议,达达集团旗下京东到家将基于提升流量和效率两大核心方向,与丝芙兰在小米OLED电视新品重磅发布!联发科芯片助力打造大屏高端画质最近,小米的热度非常高,除了雷军演讲之外,还推出了不少新产品,小米MIX4和小米平板5,不过,最受关注的还是小米电视6OLED,亮点有很多。小米电视6OLED电视拥有两个版本,分别让你的微信更炫彩微信现在已经是所有智能手机的必备app了,从开机那一刻,手机就自带的有,基础用户更是高达十亿以上。但是,有一项隐藏的功能可不是人人都知道的。相信大家一定都使用过微信的语音聊天和视频人脸识别算法原理一人脸验证VS人脸识别验证一对一关系匹配识别数据库中存在多个数据,进行一对多的匹配人脸验证的准确率很高,不代表人脸识别准确率很高,错误率会被放大二oneshot学习有一种考虑方式是
直播创新新时代?看看智云和快手是怎么做的很多人都喜欢看直播吧?不过大部分人并不知道,其实直播的背后还有很多学问,比如直播的机位设置,手机的角度等等,要想做好直播真的不是那么容易。不过,近日国内短视频直播平台快手就和稳定器全国第十一届残运会暨第八届特奥会开幕式明晚起航全国第十一届残运会暨第八届特奥会开幕式明晚起航中华人民共和国第十一届残疾人运动会暨第八届特殊奥林匹克运动会(以下简称残特奥会)开幕式定于10月22日晚上8时在西安奥体中心体育馆举行消防安全教育讲座活动为切实增强辖区居民的消防安全意识和自救防范能力,9月15日下午,盘溪第一社区组织开展了一场消防安全讲座活动,现场共有20名居民参加讲座,学习消防安全标识。本次活动邀请专业导师现场讲阿里腾讯字节跳动等互联网巨头风云再起威观察互联网巨头风云再起一场旷日持久席卷整个互联网江湖,由阿里腾讯字节跳动等互联网各大门派参与的江湖纷争即将在掌门人工信部的组织下落下帷幕。从此,互联网江湖格局或将再次发生深刻变化解密马云退休当老师的六大真实原因第46期威观察编辑风儿来源微信公众号东威智库缘起教育头条位,马云已包揽马云要当老师,只在阿里保留董事身份。消息一出,迅速爆红网络。从新闻版到科技版到金融版到娱乐版,马云自带IP,其央行征信即将接入,被阿里花呗毁掉的一代将会怎样?威观察被花呗毁掉的一代继4月12日,人民银行银保监会证监会外汇局等金融管理部门再次联合约谈蚂蚁金服。今天,阿里又摊上大事了!花呗将全面接入央行征信系统冲上热搜榜,话题瞬间被引爆了很盘一社区开展科普健康讲座活动为进一步营造爱科学学科学用科学的良好氛围,倡导科学生活,7月12日,盘溪第一社区组织辖区老年人开展了一场健康科普知识讲座。活动过程中,社工详细向居民具体讲解健康的四大要素,包括合理520心理特辑一生勾引了132位女性的意大利情圣卡萨诺瓦网友咿咿提问男朋友追我的时候我问他是不是只是因为我单身所以追我,他说周围单身妹子很多但是他和她们最多只是朋友,没有追过哪个。但是最近同事和我说他其实在我上班之前追过我们单位的两个女面对已经失约第五次的男友,一句话比指责抱怨更有震慑力网友男朋友由于工作原因生物钟很乱,该睡的时候不睡,不该睡的时候睡到死,今天是他失约第五次了,每次他就睡着我等着。烦死了,我该怎么办?你好,感谢信任,我是心融有道心理工作室里的咨询师客厅变影院?最懂用户心的中国移动即将解锁线上观影新场景如果要选出最受当代人喜爱的娱乐消遣方式,相信不少人会为看电影投上一票吧?从露天电影时代的万人空巷到如今实体电影院的遍地开花,电影承载了许多国人难忘的休闲时光,也在技术迭代中不断解锁回顾移动人眼中的全员核酸检测应急演练常州市各地核酸检测应急演练已全部完成,所有样本检测结果均为阴性。58个采样点,近36万人受检,稳中有序,忙而不乱。多方疫情防控人员都投身到这场没有硝烟的战斗中,用汗水为大家筑起了安