[优化]Java中大文件IO的优化策略

Java中的IO方式大致分为如下几种

  1. 普通IO,也叫做BIO,基于流模型的阻塞式IO,相关的类大部分都是InputStream,OutputStream,Reader,Writer下的子类。
  2. NIO,也是大家认为效率较高的IO方式之一,相关的类有 ByteBuffer,FileChannel等。
  3. mmap内存映射,这是一种将文件直接映射到内存地址的方式,是一种非常快速的IO方案,相关的类有FileChannel,MappedByteBuffer

但是在分析各种IO方式的优化策略的时,首先至少需要了解一下,使用Java进行一次磁盘读取,到底进行了那些步骤?

标准的一次文件读肯定涉及以下几个拷贝步骤

  1. 将数据从硬件读取到内核态的内核缓冲区中
  2. 将内核缓冲区的数据读取到用户态的 JVM 中

此外,底层通过 write 、read 等函数进行 IO 系统调用时,需要传入数据所在缓冲区起始地址和长度,但是由于我们使用的是 Java,Java 中的对象存在 Java 的堆中,由于 GC 的存在,对象在堆中的位置是会不断变动的,所以在用户态的 JVM 和 内核缓冲区之间,还有一个不会被 GC 所干扰的堆外内存区作为缓冲区,所以这里又多了一个拷贝步骤。

浅析Java强大的动态Instrumention能力

前言

在前面的博客中,我写过一句话,叫做

Java世界里的一切东西都是在拼Java命令行参数

如果你使用IDEA,并且在运行 Java 代码时观察过 IDEA 帮我们拼出来的命令行参数,举个例子

D:\jdk8\jdk1.8.0_232\bin\java.exe "\"-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 201.4865.12\lib\idea_rt.jar=61840:C:\Program Files\JetBrains\IntelliJ IDEA 201.4865.12\bin\"" -Dfile.encoding=UTF-8 -classpath ( 省略一系列依赖Jar包 ) C:\Users\25959\Desktop\test\target\classes com.ayang818.test.Test

这是我运行一个很简单的程序,IDEA 帮我们拼出来的命令行参数,其中 -Dfile.encoding 和 -classpath 我们都很熟悉,一个是指定编码方式,另一个是指定 classpath 路径。但是有一个我们可能很陌生的参数,叫做 -javaagent , agent 翻译成中文是代理的意思。于是我开始了一天的探究过程。

巧妙使用位运算

巧妙使用位运算 && Leetcode 421 Maximum XOR of Two Numbers in an Array

部分参考 : 全网把Map中的hash()分析的最透彻的文章,别无二家。

在学习ConcurrentHashMap的分段锁机制时,对于根据hashcode的一些操作结果,分配锁数组中的锁对象的机制不是很理解。于是看了看开头提到的文章,确实理解了很多。中间看着有些磕磕绊绊,主要是不是很明白其中一些位运算道理在做什么。举个栗子

Java中的锁优化(1)

部分内容参考《深入理解Java虚拟机》第五部分——高效并发

锁优化

高效并发是JDK1.5-JDK1.6的一个重要改进,HotSpot虚拟机团队在开发这个版本的时候花了大量的精力去实现各种锁优化技术,比如适应性自旋,锁消除,锁粗化,轻量级锁和偏向锁等,这些技术都是为了在线程之间更加高效的共享数据,以及解决竞争问题。这篇文章将以概念介绍为主。

自旋锁与自适应自旋

我们知道往往在讨论锁的互斥同步的时候,其对性能最大的损耗就是阻塞的实现,挂起线程和回复线程都要进入操作系统内核态完成。然而其实有些阻塞只是很短的时间,没有必要挂起线程,所以这个时候可以选择让线程进入一个忙循环,知道阻塞条件结束,这就是所谓的自旋锁,关于自旋的代码可以参照我的这篇文章——Java原子性操作以及不如来手写一个简单锁,由于自旋是不断重试的过程,要是一直重试失败,就会造成CPU资源浪费,所以自旋需要设置次数;而所谓自适应自旋就是指根据前一次在同一个锁上的自旋时间,以及锁的拥有者的状态来判断自旋次数或是否自旋,这些在JDK1.6中都已经帮我们实现了。

Leetcode的几道有意思的多线程题

前记

最近一直在看Java的多线程编程,但苦于这东西有点过于偏向理论,结果今天上了Leetcode上看了下,发现居然有多线程相关的题目,(虽然只有五题),顺便放个链接吧,题目链接。题目感觉就是让你使用一些同步工具类或者锁或其他机制来完成要求,挺有意思的.

Java中的对象锁(Monitor)

Java中的对象锁

说到对象锁,要与之对比就不得不讲到类锁。在写单例模式的时候其实经常会用在双重校验锁中用到类锁,如下面的代码

public ClassLock {
priavte volatiled ClassLock classLock;

private ClassLock() {
// init
}

public ClassLock getInstance() {
if (classLock == null) {
synchronized (ClassLock.class) {
if (classLock == null) {
classLock = new ClassLock();
}
}
}
return classLock;
}
}

可以看到在上面的代码中我们是对一整个类进行加锁,包括直接在方法签名上使用synchronized关键字,这都是属于类锁的范畴。因为在调用一个类的实例的时候,当运行其中一个加锁的方法时,其他加锁的方法是不可以执行的。也就是说一个类其实只有一个类锁,它锁住的对象是一个类。但是对象锁不一样,一个类中可以有多个对象,也就是说对象锁在一个类的实例中不止一个, 而每个对象都可以成为一个Monitor。对象锁往往用于多个线程之间的协作,与之配套的工具是synchronized,wait,notify,notifyAll。

IDEA远程调试

java世界里的一切东西都是在拼Java命令行参数

Debug之前

调试一切Java程序,想清楚两点

  • 想清楚要调试的代码跑在哪个JVM中
  • 找到要调试的源代码

随时随地Debug

java -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=1044 FileName

Java的几种同步工具类(闭锁的实现)

什么是闭锁

闭锁是一种同步工具类,可以延迟线程的进度知道其进入终止状态。闭锁的作用就像是一扇门,在闭锁结束状态之前,这扇门就是关闭的,没有任何线程可以通过。当这扇门开启的时候,闭锁将不会改变状态,会一直维持开启的状态。闭锁可以用来确保某些活动直到其他活动都完成后才可以继续执行。

CountDownLatch实现

CountDownLatch主要有两个重要的方法。

// 次数减去1
#countDown();
// 等待直到次数为0
#await();

下面的栗子体现了闭锁的等待作用

public static Long timeTasks(Integer taskNum) throws InterruptedException {
final CountDownLatch startGate = new CountDownLatch(1);
final CountDownLatch endGate = new CountDownLatch(taskNum);
for (int i = 0; i < taskNum; i++) {
int finalI = i;
new Thread(() -> {
try {
System.out.println(Thread.currentThread().getName() +" is ready");
startGate.await();
try {
Thread.sleep(2000);
System.out.println(Thread.currentThread().getName() + " thread is start");
} finally {
endGate.countDown();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}

long start = System.currentTimeMillis();
// 在主线程中一起释放
startGate.countDown();
endGate.await();
long end = System.currentTimeMillis();
return end - start;
}

设计模式(5)——观察者模式

观察者模式是什么

一句话,观察者模式(Observer Pattern)就是一种 “发布者-订阅者” 的模式。有时也被称为 “模型-视图”模式、“源-监听者”模式等。在这种模式中,由一个目标对象来管理所有依赖与它的观察者对象,并且当这个目标对象自身发生改变时,会主动向它的观察者们发出通知。

类比举例

比如你最近在追一个美剧《生活大爆炸》,假设著名在线视频网站某狐买下独家版权,在线更新与播放。于是你天天等啊等啊,等它的更新通知一来,你就去看那些最新的视频。

设计模式(4)——装饰器模式

装饰器模式

在接触Java之前,我接触过Python,在python中其实就有装饰器这个说法,装饰器模式的意思也差不多,就是动态的将新的职能附加到已有对象上,实现功能拓展。在阿里巴巴Java开发手册中其实有这么一段话

他告诉我们聚合和组合是要优先于继承的,若要使用继承,必须符合里氏代换原则。目的就是方便解耦。

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×