Java核心技术面试精讲
杨晓峰
前Oracle首席工程师
立即订阅
43250 人已学习
课程目录
已完结 43 讲
0/4登录后,你可以任选4讲全文学习。
开篇词 (1讲)
开篇词 | 以面试题为切入点,有效提升你的Java内功
免费
模块一 Java基础 (14讲)
第1讲 | 谈谈你对Java平台的理解?
第2讲 | Exception和Error有什么区别?
第3讲 | 谈谈final、finally、 finalize有什么不同?
第4讲 | 强引用、软引用、弱引用、幻象引用有什么区别?
第5讲 | String、StringBuffer、StringBuilder有什么区别?
第6讲 | 动态代理是基于什么原理?
第7讲 | int和Integer有什么区别?
第8讲 | 对比Vector、ArrayList、LinkedList有何区别?
第9讲 | 对比Hashtable、HashMap、TreeMap有什么不同?
第10讲 | 如何保证集合是线程安全的? ConcurrentHashMap如何实现高效地线程安全?
第11讲 | Java提供了哪些IO方式? NIO如何实现多路复用?
第12讲 | Java有几种文件拷贝方式?哪一种最高效?
第13讲 | 谈谈接口和抽象类有什么区别?
第14讲 | 谈谈你知道的设计模式?
模块二 Java进阶 (16讲)
第15讲 | synchronized和ReentrantLock有什么区别呢?
第16讲 | synchronized底层如何实现?什么是锁的升级、降级?
第17讲 | 一个线程两次调用start()方法会出现什么情况?
第18讲 | 什么情况下Java程序会产生死锁?如何定位、修复?
第19讲 | Java并发包提供了哪些并发工具类?
第20讲 | 并发包中的ConcurrentLinkedQueue和LinkedBlockingQueue有什么区别?
第21讲 | Java并发类库提供的线程池有哪几种? 分别有什么特点?
第22讲 | AtomicInteger底层实现原理是什么?如何在自己的产品代码中应用CAS操作?
第23讲 | 请介绍类加载过程,什么是双亲委派模型?
第24讲 | 有哪些方法可以在运行时动态生成一个Java类?
第25讲 | 谈谈JVM内存区域的划分,哪些区域可能发生OutOfMemoryError?
第26讲 | 如何监控和诊断JVM堆内和堆外内存使用?
第27讲 | Java常见的垃圾收集器有哪些?
第28讲 | 谈谈你的GC调优思路?
第29讲 | Java内存模型中的happen-before是什么?
第30讲 | Java程序运行在Docker等容器环境有哪些新问题?
模块三 Java安全基础 (2讲)
第31讲 | 你了解Java应用开发中的注入攻击吗?
第32讲 | 如何写出安全的Java代码?
模块四 Java性能基础 (3讲)
第33讲 | 后台服务出现明显“变慢”,谈谈你的诊断思路?
第34讲 | 有人说“Lambda能让Java程序慢30倍”,你怎么看?
第35讲 | JVM优化Java代码时都做了什么?
模块5 Java应用开发扩展 (4讲)
第36讲 | 谈谈MySQL支持的事务隔离级别,以及悲观锁和乐观锁的原理和应用场景?
第37讲 | 谈谈Spring Bean的生命周期和作用域?
第38讲 | 对比Java标准NIO类库,你知道Netty是如何实现更高性能的吗?
第39讲 | 谈谈常用的分布式ID的设计方案?Snowflake是否受冬令时切换影响?
周末福利 (2讲)
周末福利 | 谈谈我对Java学习和面试的看法
周末福利 | 一份Java工程师必读书单
结束语 (1讲)
结束语 | 技术没有终点
Java核心技术面试精讲
登录|注册

第12讲 | Java有几种文件拷贝方式?哪一种最高效?

杨晓峰 2018-05-31
我在专栏上一讲提到,NIO 不止是多路复用,NIO 2 也不只是异步 IO,今天我们来看看 Java IO 体系中,其他不可忽略的部分。
今天我要问你的问题是,Java 有几种文件拷贝方式?哪一种最高效?

典型回答

Java 有多种比较典型的文件拷贝实现方式,比如:
利用 java.io 类库,直接为源文件构建一个 FileInputStream 读取,然后再为目标文件构建一个 FileOutputStream,完成写入工作。
public static void copyFileByStream(File source, File dest) throws
IOException {
try (InputStream is = new FileInputStream(source);
OutputStream os = new FileOutputStream(dest);){
byte[] buffer = new byte[1024];
int length;
while ((length = is.read(buffer)) > 0) {
os.write(buffer, 0, length);
}
}
}
或者,利用 java.nio 类库提供的 transferTo 或 transferFrom 方法实现。
public static void copyFileByChannel(File source, File dest) throws
IOException {
try (FileChannel sourceChannel = new FileInputStream(source)
.getChannel();
FileChannel targetChannel = new FileOutputStream(dest).getChannel
();){
for (long count = sourceChannel.size() ;count>0 ;) {
long transferred = sourceChannel.transferTo(
sourceChannel.position(), count, targetChannel); sourceChannel.position(sourceChannel.position() + transferred);
count -= transferred;
}
}
}
当然,Java 标准类库本身已经提供了几种 Files.copy 的实现。
对于 Copy 的效率,这个其实与操作系统和配置等情况相关,总体上来说,NIO transferTo/From 的方式可能更快,因为它更能利用现代操作系统底层机制,避免不必要拷贝和上下文切换。

考点分析

今天这个问题,从面试的角度来看,确实是一个面试考察的点,针对我上面的典型回答,面试官还可能会从实践角度,或者 IO 底层实现机制等方面进一步提问。这一讲的内容从面试题出发,主要还是为了让你进一步加深对 Java IO 类库设计和实现的了解。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《Java核心技术面试精讲》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(46)

  • 13576788017
    杨老师,想问一下,一般要几年java经验才能达到看懂你文章的地步??我将近一年经验。。我发现我好几篇都看不懂。。底层完全不懂。。是我太菜了吗。。

    作者回复: 非常抱歉,具体哪几篇?公司对一年经验的工程师要求应该也不一样的

    2018-05-31
    1
    96
  • 行者
    可以利用NIO分散-scatter机制来写入不同buffer。
    Code:
    ByteBuffer header = ByteBuffer.allocate(128);
    ByteBuffer body = ByteBuffer.allocate(1024);
    ByteBuffer[] bufferArray = {header, body};
    channel.read(bufferArray);
    注意:该方法适用于请求头长度固定。

    作者回复: 赞

    2018-05-31
    68
  • 乘风破浪
    零拷贝是不是可以理解为内核态空间与磁盘之间的数据传输,不需要再经过用户态空间?

    作者回复: 嗯

    2018-05-31
    22
  • 闭门造车
    你好,我查看jdk8中的源码,看到您说的关于Files.copy其中两种是依靠transferto实现的,但是我翻看源码觉得跟您的理解不同,特来求证,源码如下: public static long copy(Path source, OutputStream out) throws IOException {
            Objects.requireNonNull(out);
            try (InputStream in = newInputStream(source)) {
                return copy(in, out);
            }
        }
            private static long copy(InputStream source, OutputStream sink)
            throws IOException
        {
            long nread = 0L;
            byte[] buf = new byte[BUFFER_SIZE];
            int n;
            while ((n = source.read(buf)) > 0) {
                sink.write(buf, 0, n);
                nread += n;
            }
            return nread;
        }
    2018-06-06
    3
    11
  • vash_ace
    其实在初始化 DirectByteBuffer对象时,如果当前堆外内存的条件很苛刻时,会主动调用 System.gc()强制执行FGC。所以一般建议在使用netty时开启XX:+DisableExplicitGC

    作者回复: 对,检测不够时会尝试调system.gc,记得老版本有并发分配bug,会出oom;netty,文中提到了,它是hack到内部自己释放...

    2018-06-01
    2
    8
  • 石头狮子
    若使用非 directbuffer 操作相关 api 的话,jdk 会将其复制为 ditrctbuff。并且在线程内部缓存该directbuffer。jdk 对这个缓存的大小并没有限制。
    之前遇到缓存的 directbuffer 过多,导致oom的情况。后续 jdk 版本加入了对该缓存的限制。
    额外一点是尽量不要使用堆内的 bytebuffer 操作 channel 类 api。
    2018-05-31
    7
  • CC
    我Nio从没接触过,很难受,两年开发的

    作者回复: 不用担心,是理解有难度吗?

    2018-06-07
    6
  • mongo
    杨老师,我也想请教,目前为止您的其他文章都理解的很好,到了上次专栏的NIO我理解的不是很好,今天的这篇可以说懵圈了。到了这一步想突破,应该往哪个方向?我自己感觉是因为基于这两个底层原理的上层应用使用的时候观察的不够深入,对原理反应的现象没有深刻感受,就是所谓还没有摸清楚人家长什么样。所以接下来我会认真在使用基于这些原理实现的上层应用过程中不断深挖和观察,比如认真学习dubbo框架(底层使用到了netty,netty的底层使用了NIO)来帮助我理解NIO。在这个过程中促进对dubbo的掌握,以此良性循环。不知道方向对不对?老师的学习方法是什么?请老师指点避坑。学习方法不对的话时间成本太可怕。

    作者回复: 我觉得思路不错,结合实践是非常好的;我自身也仅仅是理论上理解,并没有在大规模实践中踩坑,实践中遇到细节的“坑”其实是宝贝,所以你有更多优势;本文从基础角度出发,也是希望对其原理有个整体印象,至少被面试刨根问底时,可以有所准备,毕竟看问题的角度是不同的

    2018-05-31
    6
  • 夏洛克的救赎
    请问老师您有参与jdk的开发吗

    作者回复: 是的,目前lead的团队主要是QE职责

    2018-05-31
    5
  • Len
    请教老师:
    1. 经常看到 Java 进程的 RES 大小远超过设置的 Xmx,可以认为这就是 Direct Memory 的原因吗?如果是的话,可以简单的用堆实际占用的大小减去 RES 就是 Direct Memory 的大小吗?

    2.可以认为 Direct Memory 不论在什么情况下都不会引起 Full GC,Direct Memory 的回收只是在 Full GC (或调用 System.gc())的时候顺带着回收下,是吗?

    作者回复: 1,一般不是,那东西有个默认大小的,metaspace codecache等等都会占用,后面有章节仔细分析
    2,不是,它是利用sun.misc.Cleaner, 实际表现有瑕疵,经常要更依赖system gc去触发引用处理,9和8u有改进,我会有详解

    2018-05-31
    4
  • 皮蛋
    杨老师,想问下如果想学操作系统的知识,阅读什么书比较适合,初学者

    作者回复: 可以看看《深入理解计算机系统》,如果有精力,再找本linux内核并配合实验,会很有用

    2018-11-02
    3
  • 灰飞灰猪不会灰飞.烟灭
    老师,带缓冲区的io流比nio哪一个性能更好?

    作者回复: 嗯,文中提到过,不能一概而论,性能通常是特定场景下的比较才有意义

    2018-05-31
    3
  • 老陈板
    本篇文章有恍然大悟的感觉,前面段时间有一家面试问了个这样的问题,我们发现服务器内存使用得特别高,但是堆内存也比较稳定,这种场景是你你会怎么排查?这里就涉及到堆外内存相关的问题!以前不知道有NMT这个工具,然后当时没答好,导致工资少了好多,早点读这篇文章多好。另外注意,sysyem.gc不一定会立即触发fgc,有个权值

    作者回复: 一个常见例子是,创建了一堆线程,实际占用内存(RSS)远比堆本身大

    2019-02-17
    2
  • Quincy
    老师,我想问下,transferto是怎么实现的零拷贝,而避免了用户态和内核态之间转换的开销
    2018-08-08
    1
    2
  • 玲玲爱学习
    堆外缓存是否与内核缓存是同一个东西?
    2018-06-28
    2
  • Cui
    Direct Buffer 生命周期内内存地址都不会再发生更改,进而内核可以安全地对其进行访问—这里能提高性能的原因 是因为内存地址不变,没有锁争用吗?能否详细解答下?

    作者回复: 我理解不是锁的问题,寻址简单,才好更直接

    2018-05-31
    2
  • 美国的华莱士
    国外的这遍文章写的还不错,偏基础的可以参考下:
    https://www.journaldev.com/861/java-copy-file
    2019-03-30
    1
  • 罗飞
    零拷贝,是DMA 数据传输,完全由硬件实现的,内核只是起到控制设置作用,不要误人子弟好么

    作者回复: 谢谢,建议搜索下Java DMA或者相关的RDMA;
    实时上这是个一直在发展的领域,虽然因为种种原因应用场景有限,最新的API发展如RDMA相关,可以了解下 http://openjdk.java.net/jeps/337

    2019-01-10
    1
  • godtrue
    有同感,Java IO这块学起来坡度明显陡峭了,上午看各种IO就有点不在状态,估计更偏向操作系统层面了吧!
    不过我又回头看了漫画编程上关于Java IO的文章,感觉轻松自在很多,理解同步,异步,阻塞,非阻塞,各种IO的特点丝毫不费劲,估计是漫画和更通俗的原因吧!
    老师,讲文件拷贝最快的方式有数据依据吗?还是就是推论?感觉不是很确定,需要依据具体情况来定?
    2018-12-15
    1
  • 帅子
    我是做安卓开发的,对于深入理解您的文章,是否对安卓开发有帮助呢?
    2018-12-13
    1
收起评论
46
返回
顶部