Java核心技术36讲-基础部分


运行模式
  编译执行
  解释执行
  混合执行
  分层编译
  AOT(Ahead-of-Time),字节码编译为机器代码,jaotc工具

语言特性
泛型
Lambda特性
基础类库
集合
IO/NIO
网络
并发
安全
ClassLoader(Bootstrap,Application,Extension)
类的加载过程-加载,验证,链接,初始化
SerialGC,Parallel GC,CMS,G1
编译器,运行环境,安全工具,诊断和监控工具
JVM之上的其他语言

jaotc --output libHelloWorld.so HelloWorld.class
jaotc --output libjava.base.so --module java.base
java -XX:AOTLibrary=./libHelloWorld.so,./libjava.base.so HelloWorld

Throwable和两个子类
Exception,又包括可检测(checked)异常,不检测(unchecked)异常-也就是运行时异常
Error
比如
ClassNotFoundException,运行时通过Class.forName()产生的异常
NoClassDefFoundError,JVM或ClassLoader实例尝试加载类时的异常
try-catch机制,因为创建Throwable要调用native代码fillInStacktrace,会影响性能

 

fianl,并发时可以省去防御代码,JVM优化时不会final没什么用
finally
finalize,这个会影响垃圾收集性能,现在可以用幻引用+引用队列的方式替代
finalize使用不当会导致死锁,挂起等,java中调用其他语言代码时,这个函数会有用


引用类型
1.强引用
2.软引用Softly Reachable,内存不足时被回收
3.弱引用Weakly Reachable,GC时被回收
4.幻引用Phantom Reachable,始终返回null,通过引用队列可以确定此对象已被回收
引用队列,被回收的对象会放入队列中
软引用的参数
-XX:SoftRefLRUPolicyMSPerMB=N
GC的诊断参数
-XX:+PrintReferenceGC  此参数在JDK9中已不存在

 


String,StringBuffer,StringBuilder
String的intern()放入PermGen区
-XX:StringTableSize=N
-XX:+PrintStringTableStatistics  

SymbolTable statistics:
Number of buckets       :   20011
Average bucket size     :       1
Variance of bucket size :       1
Std. dev. of bucket size:       1
Maximum bucket size     :       5
StringTable statistics:
Number of buckets       :   60013
Average bucket size     :       0
Variance of bucket size :       0
Std. dev. of bucket size:       0
Maximum bucket size     :       3

intern()是一种显示的排重机制,JDK8之后可以自动排重
-XX:+UseStringDeduplication

字符串的一些基础操作会直接利用JVM内部的Intrinsic机制,运行的就是特殊优化的本地代码,不是Java代码生成的字节码,Intrinsic可以理解为一种利用native方式hard-code的逻辑,算是一种特别的内联,有多优化还是需要直接使用特定的CPU指定

java -XX:+PrintCompilation -XX:+UnlockDiagnosticVMOptions -XX:+PrintInlining [java类]
     51    1       3       java.lang.String::hashCode (55 bytes)
     52    2       3       java.lang.String::equals (81 bytes)
     53    3       3       java.lang.String::charAt (29 bytes)
                              @ 18  java/lang/StringIndexOutOfBoundsException:: (not loaded)   not inlineable
     53    4       3       java.lang.String::length (6 bytes)
     55    7     n 0       java.lang.System::arraycopy (native)   (static)
     56    5       3       java.lang.String::indexOf (70 bytes)
                              @ 66   java.lang.String::indexOfSupplementary (71 bytes)   callee is too large
     57    6       3       java.lang.Object:: (1 bytes)
     57    8       3       java.lang.Math::min (11 bytes)
     57    9       1       java.lang.ref.Reference::get (5 bytes)
     57   10       1       java.lang.ThreadLocal::access$400 (5 bytes)
     61   11       3       java.lang.AbstractStringBuilder::append (50 bytes)
                              @ 5   java.lang.AbstractStringBuilder::appendNull (56 bytes)   callee is too large
                              @ 10   java.lang.String::length (6 bytes)
                              @ 21   java.lang.AbstractStringBuilder::ensureCapacityInternal (27 bytes)
                                @ 17   java.lang.AbstractStringBuilder::newCapacity (39 bytes)   callee is too large
                                @ 20   java.util.Arrays::copyOf (19 bytes)
                                  @ 11   java.lang.Math::min (11 bytes)
                                  @ 14   java.lang.System::arraycopy (0 bytes)   intrinsic
                              @ 35   java.lang.String::getChars (62 bytes)   callee is too large
     61   12       3       java.lang.String::getChars (62 bytes)
                              @ 9  java/lang/StringIndexOutOfBoundsException:: (not loaded)   not inlineable
                              @ 27  java/lang/StringIndexOutOfBoundsException:: (not loaded)   not inlineable
                              @ 43  java/lang/StringIndexOutOfBoundsException:: (not loaded)   not inlineable
                              @ 58   java.lang.System::arraycopy (0 bytes)   intrinsic

Java9自后,引入了Compact Strings的设计,将char[]改为byte[],加载编码的coder加速了性能
相关的Intrinsic也做了重构,但对开发者是透明的
 

 


反射
Java9做了模块化对反射做了限制,但兼容老版本
静态代理,动态代理
JDK Proxy
Spring中的cglib实现
 

 

集合类
List
Set
Map
Queue/Deuqe
相关的排序算法
Java9的 List.of() 简化创建

Java核心技术36讲-基础部分_第1张图片

Hashtable,HashMap,TreeMap,LinkedHashMap
equals和hashCode
HashMap的容量(capacity)和负载系数(load factor),树化(冲突后的链表长>8)
HashMap中的hash不是用key本身的hashC偶的,而是来自于HashMap内部的另外一个hash函数
将hash的高位移到地位进行异或运算,因为有些数据计算出的哈希值差异主要在高位,而HashMap里的哈希寻址是忽略容量以上的高位,那么这种处理方式就可以有效避免类似情况下的哈希碰撞
Java核心技术36讲-基础部分_第2张图片

开放定址法
基本思想是:当关键字key的哈希地址p=H(key)出现冲突时,以p为基础,产生另一个哈希地址p1,如果p1仍然冲突,再以p为基础,产生另一个哈希地址p2,…,直到找出一个不冲突的哈希地址pi ,将相应元素存入其中。

再哈希法
这种方法是同时构造多个不同的哈希函数:
Hi=RH1(key)  i=1,2,…,k
当哈希地址Hi=RH1(key)发生冲突时,再计算Hi=RH2(key)……,直到冲突不再产生。这种方法不易产生聚集,但增加了计算时间。

链地址法
这种方法的基本思想是将所有哈希地址为i的元素构成一个称为同义词链的单链表,并将单链表的头指针存在哈希表的第i个单元中,因而查找、插入和删除主要在同义词链中进行。链地址法适用于经常进行插入和删除的情况。
 

ConcurrentHashMap 
1.7和之前的实现方式
1.分成若干segment,通过hash定位到特定的segment,每个segment里面有若桶,桶里存储KV
2.put的时候通过key得到segment并加锁,然后再hash得到要添加的桶,遍历桶中链表替换节点
3.求size是分两次计算,若两次返回相同则返回,否则加锁重新计算

1.8之后的实现方式
1.不依赖segment加锁,segment数量和桶数量一致
2.对key hash计算得到存放的桶位置,为空则用CAS设置新节点
3.否则用synchronized加锁,遍历桶中数据,替换或新添加到桶中
4.判断是否需要扩容,是否需要树化
5.求size利用LogAdd累加计算
Java核心技术36讲-基础部分_第3张图片

 

 


I/O

同步和异步
阻塞和非阻塞
IO不仅仅对文件,网络中也有
输入流,输出流,是用于读取/写入字节的
Reader/writer是用于操作字符,增加字符编码等功能
BufferedOutputStrea是带缓冲区的实现
很多IO类都实现了Closeable接口

Java核心技术36讲-基础部分_第4张图片

每个客户端对应一个线程模式

public class DemoServer extends Thread {
    private ServerSocket serverSocket;
    public int getPort() {
        return  serverSocket.getLocalPort();
    }
    public void run() {
        try {
            serverSocket = new ServerSocket(0);
			ExecutorService executor = Executors.newFixedThreadPool(8);
            while (true) {
                Socket socket = serverSocket.accept();
                RequestHandler requestHandler = new RequestHandler(socket);
                //requestHandler.start();
				executor.execute(requestHandler);
            }
        } catch (IOException e) {
           ....
        } finally {
            .....
        }
    }
    public static void main(String[] args) throws IOException {
        DemoServer server = new DemoServer();
        server.start();
        try (Socket client = new Socket(InetAddress.getLocalHost(), server.getPort())) {
            BufferedReader bufferedReader = new BufferedReader(new                   InputStreamReader(client.getInputStream()));
            bufferedReader.lines().forEach(s -> System.out.println(s));
        }
    }
 }
// 简化实现,不做读取,直接发送字符串
class RequestHandler extends Thread {
    private Socket socket;
    RequestHandler(Socket socket) {
        this.socket = socket;
    }
    @Override
    public void run() {
        try (PrintWriter out = new PrintWriter(socket.getOutputStream());) {
            out.println("Hello world!");
            out.flush();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
 }

上述代码的工作方式如下

Java核心技术36讲-基础部分_第5张图片

NIO模式的代码如下


 public class NIOServer extends Thread {
    public void run() {
        try (Selector selector = Selector.open();
             ServerSocketChannel serverSocket = ServerSocketChannel.open();) {// 创建 Selector 和 Channel
            serverSocket.bind(new InetSocketAddress(InetAddress.getLocalHost(), 8888));
            serverSocket.configureBlocking(false);
            // 注册到 Selector,并说明关注点
            serverSocket.register(selector, SelectionKey.OP_ACCEPT);
            while (true) {
                selector.select();// 阻塞等待就绪的 Channel,这是关键点之一
                Set selectedKeys = selector.selectedKeys();
                Iterator iter = selectedKeys.iterator();
                while (iter.hasNext()) {
                    SelectionKey key = iter.next();
                   // 生产系统中一般会额外进行就绪状态检查
                    sayHelloWorld((ServerSocketChannel) key.channel());
                    iter.remove();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    private void sayHelloWorld(ServerSocketChannel server) throws IOException {
        try (SocketChannel client = server.accept();) {          client.write(Charset.defaultCharset().encode("Hello world!"));
        }
    }
   // 省略了与前面类似的 main
}

上述代码的工作方式如下

Java核心技术36讲-基础部分_第6张图片

 

NIO2 是异步模式,用完成后回调实现的

AsynchronousServerSocketChannel serverSock =        AsynchronousServerSocketChannel.open().bind(sockAddr);
serverSock.accept(serverSock, new CompletionHandler<>() { // 为异步操作指定 CompletionHandler 回调函数
    @Override
    public void completed(AsynchronousSocketChannel sockChannel, AsynchronousServerSocketChannel serverSock) {
        serverSock.accept(serverSock, this);
        // 另外一个 write(sock,CompletionHandler{})
        sayHelloWorld(sockChannel, Charset.defaultCharset().encode
                ("Hello World!"));
    }
  // 省略其他路径处理方法...
});

 


文件拷贝

普通方式
NIO transferTo/From方式
Files工具类

拷贝实现机制,用户态->内核态

transferTo直接在内核态拷贝传输

Files工具类实现的拷贝,不同平台有不同的实现方式
其实只是用户态拷贝

Java核心技术36讲-基础部分_第7张图片
NIO Buffer
capcity,反映这个Buffer到底多大,也就是数组程度
position,要操作的数据起始位置
limit,   相当于操作的限额,在读取或写入时,limit设置到所容纳的数据上线,写入时设置为容量的下限
mark,    记录上一次positioni的位置,默认是0

Java核心技术36讲-基础部分_第8张图片


 
DirectBuffer
MappedByteBuffer,讲啊文件按照指定大小直接映射为内存区域
设置DirectBuffer参数

-XX:MaxDirectMemorySize=512M

DirectBuffer垃圾收集基于Cleaner和幻象引用
对irect Buffer 的回收的建议:
在应用程序中,显式地调用 System.gc() 来强制触发
另外一种思路是,在大量使用 Direct Buffer 的部分框架中,框架会自己在程序中调用释放方法,Netty 就是这么做的,有兴趣可以参考其实现(PlatformDependent0)。
重复使用 Direct Buffer


在 JDK 8 之后的版本,可以用 Native Memory Tracking(NMT)特性来进行DirectBuffer诊断,
注意,激活 NMT 通常都会导致 JVM 出现 5%~10% 的性能下降

-XX:NativeMemoryTracking={summary|detail}

注意,激活 NMT 通常都会导致 JVM 出现 5%~10% 的性能下降,请谨慎考虑。

运行时,可以采用下面命令进行交互式对比

// 打印 NMT 信息
jcmd  VM.native_memory detail 

// 进行 baseline,以对比分配内存变化
jcmd  VM.native_memory baseline
 
// 进行 baseline,以对比分配内存变化
jcmd  VM.native_memory detail.diff


//JDK 9 的输出片段如下,“+”表示的就是 diff 命令发现的分配变化:
-Internal (reserved=679KB +4KB, committed=679KB +4KB)
              (malloc=615KB +4KB #1571 +4)
              (mmap: reserved=64KB, committed=64KB)

 


设计模式可以分为创建型模式、结构型模式和行为型模式

创建型模式,是对对象创建过程的各种问题和解决方案的总结,包括

  • 各种工厂模式(Factory、Abstract Factory)
  • 单例模式(Singleton)
  • 构建器模式(Builder)
  • 原型模式(ProtoType)

结构型模式,是针对软件设计结构的总结,关注于类、对象继承、组合方式的实践经验。

  • 桥接模式(Bridge)
  • 适配器模式(Adapter)
  • 装饰者模式(Decorator)
  • 代理模式(Proxy)
  • 组合模式(Composite)
  • 外观模式(Facade)
  • 享元模式(Flyweight)

行为型模式,是从类或对象之间交互、职责划分等角度总结的模式

  • 策略模式(Strategy)
  • 解释器模式(Interpreter)
  • 命令模式(Command)
  • 观察者模式(Observer)
  • 迭代器模式(Iterator)
  • 模板方法模式(Template Method)
  • 访问者模式(Visitor)

 

 

 

 

 

 

参考

Java技术36讲-笔记

 

 

你可能感兴趣的:(编程语言)