Java
JDK / SDK / IDE 理解。
特性:简单、OO、健壮(强类型语言、GC)、多线程、持久性和可移植性(体系结构中立)、解释执行和高性能(字节码以及 JVM)、分布式、动态性。
Java SE / Java EE
Basic
// comments
/** /
/**
*
*/
// 8 basic data type
// Java是强类型化的语言,但其基本类型不具备面向对象的能力
// 注意:java能够完全确定数据大小,而并不会依据平台大小而定。
byte a = '8';
short b = 16;
int c = 32; // 4 bytes
long d = 64; // 8 bytes
float e = 32; // 4 bytes
double f = 64; // 8 bytes
boolean g = true;
char h = 16; // 2 bytes
// object literal
0b110011
022347
0xeffdd12
// Array & ArrayList
int[] c = new int[12];
int[][] d = new int[3][4];
// Enum 注意:每一个枚举的常量都是公开的、静态的、final 的
public enum Person {
WangGang ( "Cute,Strong,Happy!" ), LiuJunbo ( "Man,Strong,Cute!" ), YangHanshu ( "Fat,Hairy" ), DengYucun ( "Supper Cute" ), YuJie ( "Handsome,Man" );
}
public class Algorithms {
// Java does not allow a static method to access non-static members of the same class directly.
// 它们只能调用其它静态方法
// 它们只能够直接访问静态数据
// 它们不能够以任何方式引用this或者super
public static int numberSeq[] = {
1, 7, 3, 15, 22, 42, 18, 9, 7
};
// Test char sequence
public static char charaterSeq[] = {
'd', 'f', 'c', 'k', 'f', 'g', 'm', 'i', 'z'
};
// Main function to execute
public static void main (String[] args) {
System.out.println("hello,world!");
System.out.println(SearchAlgorithms.binarySearch(Algorithms.numberSeq, 42));
}
}
abstract class Strategy {
public static int algorithm = null;
// 对方法而言,禁止重写类中的任何方法和成员
// 对类而言,禁止被继承
public final String getAlgorithmName(String type) {
return this.algorithm;
}
// transient 实例变量值不需要永久储存 will not persist
// volatile 该修饰的变量可以被程序的其他部分随意修改
// protected Using protected access offers an intermediate level of access between public and private. A superclass’s protected members can be accessed by members of that superclass, by members of its subclasses and by members of other classes in the same package—protected members also have package access.
// the private field can manipulated only by its methods.
// the default field can be visited or be called or be used in any field of Java Project.
}
Basic Type Series
// String
String str = new String('abcd');
str.length // 4
str.charAt();
str.getChar();
str.indexOf();
str.lastIndexOf();
str.substring();
str.concat();
str.replace();
str.toUpperCase();
str.toLowerCase();
str.trim();
str.toCharArray();
str.valueOf();
str.toString();
// ...
// More Strin Related Class
public class StringBuilder {}
public class Character {}
// regular expression
fileName.match("[A-Z]*");
// see the Java API Doc
OO in Java
- 抽象类:抽象类中的方法必须被子类实现,抽象类只能够被继承不能够被实例化。
- Package:分类保存各种各样的类,并且允许不同Package下的类名重复,将类的命名空间划分为更便于管理的块,也便是包,包既是一种命名机制,也是一种可见性的控制机制。
- Interface:与抽象类相似,但是允许一个类对应多个接口,使用
interface
可以指定类的操作,但是现在还不能够进行这些操作;接口中:不含实例变量,但是可以申请变量,这类变量被隐式定义为:final static
。为了实现接口,类必须定义为实现接口所定义的方法集。- 注意:实现接口方法的时候,必须声明其为
public
。
- 注意:实现接口方法的时候,必须声明其为
super
可以引用超类的实例。@override
重载。如果子类的一个方法和超类的某个方法具有相同的名称和类型签名。那么子类也便重写了超类之中对应的方法。覆盖之后调用方法之时,调用子类方法,而super.show()
类似的表达能够调用超类的 show 方法。- 多态:一个接口,多个方法的概念,而方法重载是实现多态的机制。
- 泛型:意思是参数化类型。使用该特性创建的类、接口以及方法可以作为参数指定操作数据的类型。例如:使用泛型可以创建自动操作不同类型的数据类。
class Gen<T> {
public T name;
// T是类型的参数名称
// 这个名称是实际类型的占位符,当创建对象的时候,将实际类型传递给Gen
// T 也就代替了所谓的不确定类型
public static T getName(T type) {
return this.name;
}
}
Exception
Java 异常是用来描述在一段代码中发生的异常情况(也就是错误)的对象。当出现引起异常的情况时,就会创建用来表示异常的对象,并在引起错误的方法之中抛出异常的对象。采用这种机制可以自己处理异常也可以继续传递异常。
try {
// do something
} catch (IllegalArgumentException) {
// 手动地抛出异常,使用 throw关键词
throw new XXException();
} finally {
// do something
}
// 从方法抛出的异常都必须经过一条 throws 的语句进行指定
static string getPackageName() throws IllegalArgumentException {
}
Java I/O
I/O 问题是 Web 应用面临的最重要的问题之一,其主的操作类在 java.io
下,大概 80+ 个类。主要分为四类:
- 基于字节操作的 I/O 接口:
InputStream
/OutputStream
SockectInputStream -> FileInputStream -> InputStream
- 操作数据的方式是可以 组合 使用的。
- 必须指定流最终写出到什么地方。
OutputStream stream = new BufferOutputStream(
new ObjectOutputStream(
new FileOutPutStream("filename")
)
);
一般说来流的 I/O 类型主要包括:ByteArrayStream
FileStream
SocketStream
FilterStream
BufferStream
ObjectStream
PipedStream
…
- 基于字符操作的 I/O 接口:
Writer
/Reader
字节和字符的转化接口是由 StreamEncoder / StreamDecoder
实现的。
- 基于磁盘操作的 I/O 接口:
File
四种基本的磁盘 I/O 机制:
- 标准访问:用户地址空间
<-->
系统地址空间,磁盘高速页缓存,应用缓存之间的调用过程。 - 直接 I/O 访问:不通过内核之中的高速页面缓存,直接访问磁盘地址。
- 同步文件访问 / 异步文件访问
- 内存映射:将操作系统中内存中的某一片区域与磁盘文件关联起来,当访问内存中的一段数据的时候,转换为访问文件的某一段数据。
Java 通过传入文件路径之后,创建 File
对象来标识这个文件,随后创建「真正」读取文件的操作对象 FileDescriptor
来关联真实存在的磁盘文件以便于直接控制。同时会使用 StreamDecoder
来将字节流转换为字符流。至于如何从磁盘驱动器上读取字符,则交由操作系统的 I/O API 完成。
- 基于网络操作的 I/O 接口:
Socket
Socket
是一个具有操作计算机之间通过网络来通信的抽象功能。大部分情况下都是使用基于 TCP/IP
的流套接字,是一种稳定的通信协议。
Java 也是如此,通过一个 Socket
实例来表示唯一一个主机上的应用程序的通信链路。一般由以下过程实现:
- 调用操作系统创建
Socket
实例,分配本地端口号,包括:本地地址、远程地址以及端口号的套接字数据结构。随后执行 TCP 3次握手完成对Socket
实例的创建。 Socket
实例具有InputStream
和OutputStream
来交换数据。其中还会引入:缓冲区以及队列机制。
BIO v.s. NIO
- BIO 采用的线程阻塞的方式,对大规模访问及其不友好,虽然可以使用「线程池」的概念来改良。
- NIO 使用了 Buffer / Selector / Channel 的协作实现非阻塞式 I/O。即:Selector 检测到 Channel 有 I/O 数据传输时,将数据写入 Buffer 缓冲区,再根据调度读取数据的过程。
Buffer 的工作机制:
capacity / limit / position / mark
。ByteBuffer
v.s.DirectByteBuffer
,前者需要拷贝到JavaHeap
中,后者可以直接通过 Native 代码操作非 JVM 中的内存空间,可以减少内存复制开销,需要System.gc()
手动清除内存空间,存在 Native 内存泄露以及内存回收开销较大的缺点。适合 数据量较大、生命周期较长 的数据存取操作。
I/O 优化思路
- 磁盘 I / O 优化
- 性能检测:I / O wait 指标占 CPU 时间,可以通过
iostat
;还可以通过 IOPS 了解磁盘性能; - 缓存思路:增加应用层缓存,多层缓存架构设计。
- 优化磁盘管理系统,寻址策略等,在操作系统层优化,包括
Network File System
等。 - 使用 RAID 提高磁盘性能。其中 RAID-0 数据平均写入多个磁盘阵列;RAID-1 镜像备份;RAID-5 引入奇偶校验取代镜像备份;RAID 1+0 分组和备份并行。
- 性能检测:I / O wait 指标占 CPU 时间,可以通过
- 网络 I / O 优化
- 调节 TCP 参数,如:
time_wait
/tcp_window_scaling
等优化网络控制。 - 应用层减少请求次数、压缩数据、减少编码次数。
- 合理使用网络交互方式,包括:同步、异步、阻塞、非阻塞。
- 同步阻塞:最常规模式,I / O 性能一般很差,而且 CPU 大部分处于空闲态。
- 同步非阻塞:提升 I / O 性能的常规手段,但会增加 CPU 消耗。比如:网络 I / O 是长连接但是同时传输数据量又不大的情况下,对 I / O 性能提升明显。
- 异步阻塞:能够提升 I / O 效率,比如在分布式数据库中,主数据库记录一般使用同步阻塞,但是备份数据库使用异步阻塞可以提高 I / O 操作效率。
- 异步非阻塞:一般在复杂情形下使用,比如:集群之间的消息同步机制。
- 调节 TCP 参数,如:
MultiThread
JVM
体系结构:类加载器、执行引擎(基于栈结构)、内存区、本地方法调用。
- 指令集
- 计算单元
- 寻址模式
- 寄存器定义:
- 存储单元:磁盘、内存和内核缓存。
JIT:对于经常执行的方法会编译为 Native 代码来执行。
JVM 的内存管理:
理解「物理内存」和「虚拟内存」
理解「内核空间」和「用户空间」
JVM 的运行时数据:寄存器数据、Java 栈、堆、方法区(存储类结构信息)、本地方法区(本地方法栈)、运行时常量池。
JVM 内存回收策略:
垃圾检测策略:不能够被「根对象」集合引用到达的对象,被视为非活动对象,可以被垃圾回收。
基于「分代」的垃圾回收算法将内存分为「Old」&「Young」,从而以不同的 GC 频率来提高 GC 效率。
- 扩展阅读: 阿里 HBase 内存 AliGC 回收策略
内存问题分析:堆内存占用检测、Native 内存 free() 检测。
Servlet
ServletContainer 容器
架构:
ServletContext
Web 请求 / 响应传递的上下文。ServletConfig
决定 Context 的配置。ServletRequest
请求封装。ServletResponse
响应封装。
Tomcat
核心概念:「Connector」和「Container」。Container 负责处理业务逻辑,Connector 负责封装和发送请求并传递给容器,包括 Request / Response 对象并最终传递给 Servlet 容器或者其它容器。两者合并在一起叫做 Service。
LifeCycle
的接口被 Service 等类实现,用于管理其生命周期。包括:如何初始化,如何结束服务,如何访问别的 Service 等等。也是基于典型的 Observer
设计模式实现。
Container 容器的设计是基于「Chain of Responsibility」设计模式来设计的。从 Engine 容器开始包含 Host(一个虚拟主机)再包含 Context 容器(代表 Servlet 的运行上下文)以及 Context 下的 Wrapper 容器(负责管理 Servlet)。它们之间使用责任链的方式传递类似 invoke
方法,使之能够动态增加和删除关系链中的成员,做到解耦合。