Java

JDK / SDK / IDE 理解。

特性:简单、OO、健壮(强类型语言、GC)、多线程、持久性和可移植性(体系结构中立)、解释执行和高性能(字节码以及 JVM)、分布式、动态性。

Java SE / Java EE

Basic

  1. // comments
  2. /** /
  3. /**
  4. *
  5. */
  6. // 8 basic data type
  7. // Java是强类型化的语言,但其基本类型不具备面向对象的能力
  8. // 注意:java能够完全确定数据大小,而并不会依据平台大小而定。
  9. byte a = '8';
  10. short b = 16;
  11. int c = 32; // 4 bytes
  12. long d = 64; // 8 bytes
  13. float e = 32; // 4 bytes
  14. double f = 64; // 8 bytes
  15. boolean g = true;
  16. char h = 16; // 2 bytes
  17. // object literal
  18. 0b110011
  19. 022347
  20. 0xeffdd12
  21. // Array & ArrayList
  22. int[] c = new int[12];
  23. int[][] d = new int[3][4];
  24. // Enum 注意:每一个枚举的常量都是公开的、静态的、final 的
  25. public enum Person {
  26. WangGang ( "Cute,Strong,Happy!" ), LiuJunbo ( "Man,Strong,Cute!" ), YangHanshu ( "Fat,Hairy" ), DengYucun ( "Supper Cute" ), YuJie ( "Handsome,Man" );
  27. }

  1. public class Algorithms {
  2. // Java does not allow a static method to access non-static members of the same class directly.
  3. // 它们只能调用其它静态方法
  4. // 它们只能够直接访问静态数据
  5. // 它们不能够以任何方式引用this或者super
  6. public static int numberSeq[] = {
  7. 1, 7, 3, 15, 22, 42, 18, 9, 7
  8. };
  9. // Test char sequence
  10. public static char charaterSeq[] = {
  11. 'd', 'f', 'c', 'k', 'f', 'g', 'm', 'i', 'z'
  12. };
  13. // Main function to execute
  14. public static void main (String[] args) {
  15. System.out.println("hello,world!");
  16. System.out.println(SearchAlgorithms.binarySearch(Algorithms.numberSeq, 42));
  17. }
  18. }
  19. abstract class Strategy {
  20. public static int algorithm = null;
  21. // 对方法而言,禁止重写类中的任何方法和成员
  22. // 对类而言,禁止被继承
  23. public final String getAlgorithmName(String type) {
  24. return this.algorithm;
  25. }
  26. // transient 实例变量值不需要永久储存 will not persist
  27. // volatile 该修饰的变量可以被程序的其他部分随意修改
  28. // 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.
  29. // the private field can manipulated only by its methods.
  30. // the default field can be visited or be called or be used in any field of Java Project.
  31. }

Basic Type Series

  1. // String
  2. String str = new String('abcd');
  3. str.length // 4
  4. str.charAt();
  5. str.getChar();
  6. str.indexOf();
  7. str.lastIndexOf();
  8. str.substring();
  9. str.concat();
  10. str.replace();
  11. str.toUpperCase();
  12. str.toLowerCase();
  13. str.trim();
  14. str.toCharArray();
  15. str.valueOf();
  16. str.toString();
  17. // ...
  18. // More Strin Related Class
  19. public class StringBuilder {}
  20. public class Character {}
  21. // regular expression
  22. fileName.match("[A-Z]*");
  23. // see the Java API Doc

OO in Java

  • 抽象类:抽象类中的方法必须被子类实现,抽象类只能够被继承不能够被实例化。
  • Package:分类保存各种各样的类,并且允许不同Package下的类名重复,将类的命名空间划分为更便于管理的块,也便是包,包既是一种命名机制,也是一种可见性的控制机制。
  • Interface:与抽象类相似,但是允许一个类对应多个接口,使用 interface 可以指定类的操作,但是现在还不能够进行这些操作;接口中:不含实例变量,但是可以申请变量,这类变量被隐式定义为:final static。为了实现接口,类必须定义为实现接口所定义的方法集。
    • 注意:实现接口方法的时候,必须声明其为 public
  • super 可以引用超类的实例。
  • @override 重载。如果子类的一个方法和超类的某个方法具有相同的名称和类型签名。那么子类也便重写了超类之中对应的方法。覆盖之后调用方法之时,调用子类方法,而 super.show() 类似的表达能够调用超类的 show 方法。
  • 多态:一个接口,多个方法的概念,而方法重载是实现多态的机制。
  • 泛型:意思是参数化类型。使用该特性创建的类、接口以及方法可以作为参数指定操作数据的类型。例如:使用泛型可以创建自动操作不同类型的数据类。
  1. class Gen<T> {
  2. public T name;
  3. // T是类型的参数名称
  4. // 这个名称是实际类型的占位符,当创建对象的时候,将实际类型传递给Gen
  5. // T 也就代替了所谓的不确定类型
  6. public static T getName(T type) {
  7. return this.name;
  8. }
  9. }

Exception

Java 异常是用来描述在一段代码中发生的异常情况(也就是错误)的对象。当出现引起异常的情况时,就会创建用来表示异常的对象,并在引起错误的方法之中抛出异常的对象。采用这种机制可以自己处理异常也可以继续传递异常。

  1. try {
  2. // do something
  3. } catch (IllegalArgumentException) {
  4. // 手动地抛出异常,使用 throw关键词
  5. throw new XXException();
  6. } finally {
  7. // do something
  8. }
  9. // 从方法抛出的异常都必须经过一条 throws 的语句进行指定
  10. static string getPackageName() throws IllegalArgumentException {
  11. }

Java I/O

I/O 问题是 Web 应用面临的最重要的问题之一,其主的操作类在 java.io 下,大概 80+ 个类。主要分为四类:

  • 基于字节操作的 I/O 接口:InputStream / OutputStream
    • SockectInputStream -> FileInputStream -> InputStream
    • 操作数据的方式是可以 组合 使用的。
    • 必须指定流最终写出到什么地方。
  1. OutputStream stream = new BufferOutputStream(
  2. new ObjectOutputStream(
  3. new FileOutPutStream("filename")
  4. )
  5. );

一般说来流的 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 实例具有 InputStreamOutputStream 来交换数据。其中还会引入:缓冲区以及队列机制。

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 优化
    • 调节 TCP 参数,如:time_wait / tcp_window_scaling 等优化网络控制。
    • 应用层减少请求次数、压缩数据、减少编码次数。
    • 合理使用网络交互方式,包括:同步、异步、阻塞、非阻塞
      • 同步阻塞:最常规模式,I / O 性能一般很差,而且 CPU 大部分处于空闲态。
      • 同步非阻塞:提升 I / O 性能的常规手段,但会增加 CPU 消耗。比如:网络 I / O 是长连接但是同时传输数据量又不大的情况下,对 I / O 性能提升明显。
      • 异步阻塞:能够提升 I / O 效率,比如在分布式数据库中,主数据库记录一般使用同步阻塞,但是备份数据库使用异步阻塞可以提高 I / O 操作效率。
      • 异步非阻塞:一般在复杂情形下使用,比如:集群之间的消息同步机制。

MultiThread

JVM

体系结构:类加载器、执行引擎(基于栈结构)、内存区、本地方法调用。

  • 指令集
  • 计算单元
  • 寻址模式
  • 寄存器定义:
  • 存储单元:磁盘、内存和内核缓存。

JIT:对于经常执行的方法会编译为 Native 代码来执行。


JVM 的内存管理:

理解「物理内存」和「虚拟内存」

理解「内核空间」和「用户空间」

JVM 的运行时数据:寄存器数据、Java 栈、堆、方法区(存储类结构信息)、本地方法区(本地方法栈)、运行时常量池。


JVM 内存回收策略:

垃圾检测策略:不能够被「根对象」集合引用到达的对象,被视为非活动对象,可以被垃圾回收。

基于「分代」的垃圾回收算法将内存分为「Old」&「Young」,从而以不同的 GC 频率来提高 GC 效率。


内存问题分析:堆内存占用检测、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 方法,使之能够动态增加和删除关系链中的成员,做到解耦合。

Jetty