JDK10 揭秘

前言

Java自1995年发布至今,已经度过23个年头;JAVA也已经推出了10个大的版本,2018年3月20日正式推出JDK10正式版本。新的版本也隐藏了许多新的奥秘,那么本课就将深入浅出的探究一下JDK10新特性。

视频内容

课程简介

大家都知道开发的核心是JDK,那么每一版新的JDK发布,都标志着Java的进程,Java的前进方向。工欲善其事,必 先利其器。作为老牌军 Java 在发行二十多年的今天,战胜了C 和 C++,成为诸多开发者的宠儿,且如今从其更新速度来看,也是不甘落后。JDK 10 是 Java 10 标准版的部分实现,于 2018 年 3 月 20 日发布,改进的关键点包括一个本地类型推断、一个垃圾回收的“干净”接口。

知识点

新特性之一个局部变量类型推断

新特性之一个干净的垃圾收集器接口新特性之G1 垃圾收集器的优化

新特性之支持备用内存设备

新特性之基于Java实验性的JIT编辑器新特性之应用程序数据共享

新特性之线程本地握手

新特性之基于时间发布的版本控制

新特性之整合源树sourcetree的JDK库

第一章 OpenJDK

1.1简介

Sun 公司在 2006 年的 JavaOne 大会上称将对 Java 开放源代码,于2009年4月15日正式发布 OpenJDK。

OpenJDK做为GPL许可(GPL-licensed)的Java平台的开源化实现.从发布那一时刻起,Java社区的大众们就又开始 努力学习,以适应这个新的开源代码基础(code-base)。OpenJDK在2013年发展迅速,被著名IT杂志SD Times 评选为2013 SD Times 100,位于“极大影响力”分类第9位。在 2015 年年底,Google宣布,他们将 Oracle JavaJDK 替换为了开源的 OpenJDK。

闭源的Oracle JDK和OpenJDK之间并不存在显著的性能差异。但是,我看到 了一个明确的消息(至少是最近), 那就是开源版本总是跟随着Oracle的产品,这可能是开始评估使用开源版本的一个原因。

1.2JDK10 新特性

新的特性和增强一般通过Java Enhancement Process(JEP)或Java Community Process标准请求(JSR)进行跟踪。因为Java 10的时间线较短,范围也相对较小,所以Java 10的变更将通过JEP进行跟踪。

被包含在Java 10中的特性是那些已经处于确定或推荐状态状态的JEP,它们包括(详情页):

286:局部变量类型推断

296:统一JDK仓库

304:垃圾收集器接口

307:G1的并行Full GC

310:应用程序类数据共享

312:线程本地握手

313:移除本地报头生成工具(javah)

314:附加Unicode语言标签扩展

316:替代存储设备上的堆分配

317:基于实验Java的JIT编译器

319:根证书

322:基于时间的版本控制

第二章 下载安装

去官网下载,按步骤安装即可。略......

第三章 局部变量类型推断

3.1概述

每次JDK版本的提升,都会有很多特性出来,对于一般的程序员来讲,可以很直观学习到的就是规范了,比如JDK5中 泛型的出现,提高了程序的灵活性;又比如JDK5中增强for循环,简便了代码的书写,大大提高了开发效率……这些 例子不胜枚举,就不一一赘述了。对于JDK10来讲最为显著的就是引入了局部类型变量推断这个特性。这个特性可 以理解为是JDK8开始可推导可省略的思想的延伸。

在JDK8出现的新特性中加入了函数式接口,即适用于函数式编程场景的接口。而Java中的函数式编程体现就是

Lambda,所以函数式接口就是可以适用于Lambda使用的接口。只有确保接口中有且仅有一个抽象方法,Java中 的Lambda才能顺利地进行推导。

3.2练习:使用Lambda标准格式(有参有返回)

题目

给定一个计算器 Calcuator 接口,内含抽象方法 calc 可以将两个int数字相加得到和值:

1public interface Calculator { 
2    int calc(int a, int b);
3}

在下面的代码中,请使用Lambda的标准格式调用 方法,完成120和130的相加计算:

1public class InvokeCalc {
2    public static void main(String[] args) {
3      // TODO 请在此使用Lambda【标准格式】调用invokeCalc方法来计算120+130的结果ß
4    }
5    private static void invokeCalc(int a, int b, Calculator calculator) {
6        int result = calculator.calc(a, b);
7        System.out.println("结果是:" + result);
8    }
9}

解答

1public static void main(String[] args) {
2    invokeCalc(120, 130, (int a, int b) ‐> {return a + b;});
3}

备注:小括号代表 Caluator 接口 calc 抽象方法的参数,大括号代表 calc 的方法体。

3.3Lambda省略格式

可推导即可省略

Lambda强调的是“做什么”而不是“怎么做”,所以凡是可以根据上下文推导得知的信息,都可以省略。例如上例还可 以使用Lambda的省略写法:

1public static void main(String[] args) { 
2    invokeCalc(120, 130, (a, b) ‐> a + b);
3}

省略规则

在Lambda标准格式的基础上,使用省略写法的规则为:

1.小括号内参数的类型可以省略;

2.如果小括号内有且仅有一个参,则小括号可以省略;

3.如果大括号内有且仅有一个语句,则无论是否有返回值,都可以省略大括号、return关键字及语句分号。

3.3 局部变量类型推断

这一版本最明显的一个新特性就是局部变量类型推导,在OpenJDK JEP 286中有详细的介绍,那么本文就将深入浅出的学习一下新特性的使用方式。

OpenJDK中的 JEP指的是JDK提供了一些更好的特性和高级支持。286: Local-Variable Type Inference

概要:增强Java语言,用来将类型推断扩展到有初始值设定项的局部变量声明。

这种处理方式必须是具有可推导性的,并且具有约束条件的。

其他静态类型语言, 如 C++, Scala, 和 Go,都已经实现了局部变量类型推断。

因为Java仍缺乏这样的功能,它要求开发人员显式声明变量的预期清单类型。为了解决这个问题,Java开发工具包

( JDK)改进建议( JEP)286提出了一个上下文敏感的关键字var,允许局部变量被以下方式初始化。

描述

Java开发人员在开发过程中经常会发现标准样板代码体积臃肿。

也就是说使用变量的时候,用来声明名字重点在于名字起得是什么,重点并不是接收的数据类型。该计划限制了类 型推断的使用场景: 有初始值的局部变量, 增强型for循环中的index, 普通for循环里的局部变量。

由于var关键字是上下文敏感的,它的使用有下面的规则定义:

备注:“语法糖”是指使用更加方便,但是原理不变的代码语法。例如在遍历集合时使用的for-each语法,其实 底层的实现原理仍然是迭代器,这便是“语法糖”。从应用层面来讲,Java中的Lambda可以被当做是匿名内部 类的“语法糖”,但是二者在原理上是不同的。

它其实是个语法糖,在语义上并没有任何变化。接下来演示一下使用场景:

有初始值的局部变量:

1public static void main(String[] args){
2var itcast = new Student("KK爱Java");// 原型为 Student 类型
3}

增强型for循环中的index:

1public static void main(String[] args){
2    var list = new ArrayList<String>();// 原型为 ArrayList<String> 类型
3    list.add("1");
4    list.add("3");
5    list.add("4");
6    for (var i : list) { //原型为 String 类型
7        System.out.println(i);
8    }
9}

普通for循环里的局部变量:

 1public static void main(String[] args){
 2    var arr = new String[3];// 原型为 String[]类型
 3    arr[0]="小明";
 4    arr[1]="小红";
 5    arr[2]="小张";
 6    for (var i = 0; i < arr.length; i++) {
 7        var value = arr[i]; //原型为 String 类型
 8        System.out.println(value);
 9    }
10}

既然是可推导的,那么作为类型接收同样可以用在有返回值方法接收上,以及有返回值lambda表达式上。

1public class Student {
2    public static void main(String[] args){
3        var sum = sum(2,4);
4        var read = new Thread(()‐> System.out.println("青铜卡了好久了"));
5    }
6    public static int sum(int a ,int b){
7        return a+b;
8    }
9}

第四章 JDK10有趣的特性

4.1整合的JDK库

296:Consolidate the JDK Forest into a Single Repository

统一JDK仓库,目前,JDK9有8个不同的Mercurial存储库用于存储包含JDK的大量源代码:

(1)root,(2)corba,(3)hotspot,(4)jaxp,(5)jaxws,(6)JDK,(7)langtools,(8)nashorn。

虽然过多的存储库提供了对组成JDK的各种组件并清晰分离,但管理多个存储库存在一些主要的缺点。其中最重要 的一点是,在JDK的两个不同部分,单个错误修复程序不能被原子跟踪。例如,如果一个bug修复需要对独立存储 库中包含的系统的两个部分进行更改,那么必须提交两个提交:每个存储库中一个。这种不连续性很容易地降低项目 和源代码管理工具的可跟踪性和复杂性。 为了解决这个问题,JEP 296建议将所有现有存储库合并到一个

Mercurial存储库中。这种合并的一个次生效应是,这个单一的Mercurial存储库比现有的8个存储库要更容易的被 镜像(作为一个Git存储库)。虽然在这个整合过程中,外部开发人员有一些阻力,但是JDK开发团队似乎已经致力于 使这一更改成为JDK 10的一部分。有关更多信息,请参见JEP 296,并提议整合由Michael Redlich发布的JDK 10 OpenJDK Mercurial存储库声明。

简而言之,将 JDK 的多个存储库合并成一个,简化开发。目前的代码库被分解成了多个库,容易出现源代码的管理问题。

—— corba:不流行的多语言、分布式通讯接口

—— hotspot:Java 虚拟机

—— jaxp:XML 处理

—— jaxws:一组 XML web services 的 Java API

—— jdk:java 开发工具包

—— share:针对操作系统的部分 , 与平台无关的实现

—— langtools:Java 语言工具

—— nashorn:JVM 上的 JavaScript 运行时

4.2应用程序类数据共享

310: Application Class-Data Sharing

应用程序类数据共享,JEP 310对类数据共享(CDS)进行了扩展,JVM可以将一些类记录到一个共享的压缩文件里,在JVM下一次启动时可以将这个文件映射到JVM进程,以此来减少启动时间。该文件也可以在多个JVM间共 享,在同一个机器上运行多个JVM时,这样做可以减少内存占用。

该功能在Java 5中就已存在,但截止到Java 9,该功能只允许bootstrap类加载器加载压缩的类。JEP 310的目的是扩展该功能,让应用程序和自定义类加载器也能加载压缩的类。该特性目前仅在Oracle JDK中可用,OpenJDK并不包含该特性。JEP计划将该特性从Oracle私有仓库中迁移到公共仓库,从Java 10往后,常规版本(非LTS)将会使用OpenJDK的二进制包。此举表明有用户正在使用该特性,所以需要在OpenJDK中也支持该特性。

简而言之,应用程序类数据共享,通过跨进程共享通用类元数据来减少占用空间。启动时间也得到了改善。

4.3常规更新

313: Remove the Native-Header Generation Tool (javah)

去掉 javah 工具。

从 JDK 8 开始,javah 的功能已经集成到了 javac 中。所以,javah 可以删掉了。Java9 开始了一些对 JDK 的家务管理,这项特性是对它的延续。当编译 JNI 代码时,已不再需要单独的工具来生成头文件,因为这可以通过 javac 完成。在未来的某一时刻,JNI 将会被 Panama 项目的结果取代,但是何时发生还不清楚。

314: Additional Unicode Language-Tag Extensions

额外的 Unicode 语言标签扩展。

增强java.util.Locale和相关 API,包括:cu (货币类型)、fw (每周第一天为星期几)、rg (区域覆盖)、tz (时区)等。

316: Heap Allocation on Alternative Memory Devices

在备用内存设备上分配堆内存。

允许 HotSpot 虚拟机在备用内存设备上分配 Java 对象堆。硬件技术在持续进化,现在可以使用与传统 DRAM 具有相同接口和类似性能特点的非易失性 RAM( NV-DIMM) 。这项 JEP 将使得 JVM 能够使用适用于不同类型的存储机制的堆。

317: Experimental Java-Based JIT Compiler

实验性的基于 Java 的 JIT 编译器。

支持基于 Java 的 JIT 编译器。相关工作主要基于 Graal。Graal 也是 Java 9 中引入的 AOT 编译器的基础。乍一想, 觉得很奇怪。如果 JVM 是用 Java 编写的,那么是否需要一个 JVM 来运行 JVM ? 相应的,这导致了一个很好的镜像类比。 现实情况是,使用 Java 编写 JVM 并不意味着必须将其编译为字节码,你可以使用 AOT 编译,然后在运行时编译代码以提高性能。

319: Root Certificates

根证书。

开源 Java SE Root CA 程序中的根证书。目标是开源 Oracle 的 Java SE Root CA 程序中的根证书,以使 OpenJDK 对开发人员更具吸引力。这是 Oracle 正在努力确保 OpenJDK 二进制和 Oracle JDK 二进制功能上一样的工作的一部分,是一项有用的补充内容。

322: Time-Based Release Versioning

基于时间的版本字符串。

修改 Java SE 平台和 JDK 版本字符串机制。

Oracle Java 平台组首席架构师 Mark Reinhold 在博客上介绍了有关 Java 未来版本的一些想法(你能接受Java 9的 下一个版本是Java 18.3吗?)。他提到,Java 计划按照时间来发布,每半年一个版本,而不是像之前那样按照重要特性来确定大版本,如果某个大的特性因故延期,这个版本可能一拖再拖。 当时,Mark 也提出来一种基于时间命名版本号的机制,比如下一个将于 2018 年 3 月发布的版本,就是 18.3,再下一个版本是 18.9,依此类推。 不过经过讨论,考虑和之前版本号的兼容等问题,最终选择的命名机制是: INTERIM.

PATCH $FEATURE,每次版本发布加 1,不考虑具体的版本内容。(之前的主版本号部分)2018 年 3 月的版本是JDK 10,9 月的版本是 JDK 11,依此类推。 $INTERIM,中间版本号,在大版本中间发布的,包含问题修复和增强的版本,不会引入非兼容性修改。

第五章 JVM优化

304: Garbage-Collector Interface

307: Parallel Full GC for G1

312: Thread-Local Handshakes

304: 垃圾收集器接口,在 hotspot/gc 代码实现方面,引入一个干净的垃圾收集器接口,改进不同垃圾收集器源代码的隔离性。这样添加新的或者删除旧的 GC,都会更容易。

可以这样理解,增加GC接口意味着厂商可以更自由地选择特定的GC算法来构建JDK,因为现在有多种处于开发当 中的GC,如Shenandoah、ZGC和Epsilon,在未来可以使用这些GC算法。这样做是为了更好地模块化 HotSpot 虚拟机中的内部垃圾回收代码,使向 HotSpot 添加新的垃圾回收器更加容易。

307: G1的并行Full GC,从JDK8开始启用G1,在JDK9中移除JDK8中废除的GC组合,在32/64位服务器版配置中,

G1成为默认垃圾回收策略。使用低停顿时长的垃圾回收器如G1相较之前默认的流量优先的回收器如Parellel GC, 能为大部分用户提供更好的体验。改进G1可用性、决策和性能,弃用CMS垃圾回收器。

当在命令行指定 - XX:+UseConcMarkSweepGC时会有警告信息。G1垃圾回收器会取代大部分CMS的使用场景。

JDK10又对G1进行了提升,而且还有加入人体工学的设想(这个版本并没有),为了减少JDK 9之外的JDK版本中垃圾收集的影响,G1收集器将被并行化(以匹配并行收集器的特征)。虽然目前还没有关于这个并行化的实现细节的信息,但是可以在JEP 307规范中找到关于此更改的更多细节。有关GC实现的更多信息,请参阅Oracle的G1指南和并行收集器指南。简 单理解,解决了G1垃圾回收器的一个问题——截止到Java 9,G1的Full GC采用的是单线程算法。也就是说,G1在发生Full GC时会严重影响性能。JEP 307的目的就是要采用并行GC算法,在发生Full GC时可以使用多个线程进行 并行回收。

312: 线程本地握手,修改安全点机制,使得部分回调操作只需要停掉单个线程,而不像以前那样,只能选择或者停掉所有线程,或者都不停止。

旨在改进虚拟机性能,在应用程序线程上调用回调不再需要执行全局虚拟机安全点操作,这意味着JVM可以停止单 个线程。一些底层小改进包括:

降低堆栈跟踪取样所带来的影响(如进行profiling)。减少信号依赖以获得更好的堆栈取样。

通过停止单独线程改进偏向锁。从JVM移除了一些内存屏障。

“局部变量的类型推断”可以说是这 12 个 JEP 中最受关注的,为支持此特性,开发团队也对 Java 语言规范做了一些更改,包括改变具有相同名称的静态类型的导入规则、将 var 作为局部变量类型推断的特殊标识符等等。

此外还包括新增的 73 个标准类库,对 JVM 规范的更改,以及一些其他更改项。

第六章 新API

有 73 项新增内容添加到了标准类库中。

java.awt.Toolkitint getMenuShortcutKeyMaskEx(): 确定哪个扩展修饰符键是菜单快捷键的适当加速键。

java.awt.geom.Path2D:

void trimToSize(): 将此 Path2D 实例的容量计算到它当前的大小。应用可使用此操作将路径的存储空间最小化。这个方法也被添加到 Path2D.Double 和 Path2D.Float 类。

java.io.ByteArrayOutputStream:String toString(Charset): 重载 toString(),通过使用指定的字符集解码字节,将缓冲区的内容转换为字符串。

java**.io.PrintStream:lang.io.PrintWriter:**

这两个类都有三个新的构造函数,它们需要额外的 Charset 参数。

java.io.Reader:long transferTo(Writer): 从这个 Reader 中读取所有字符,并按照所读的顺序将字符写入给定的 Writer 。

java.lang.Runtime.Version:

有四种新方法返回新(JEP 322)版本字符串字段的整数值: feature()、interim()、patch() 和 update() 。

java.lang.StackWalker.StackFrame:

String getDescriptor(): 按照 JVM 标准返回此堆栈帧所代表的方法的描述符。

String getMethodType():返回此堆栈帧所代表的方法类型,描述参数类型和返回值类型。java.lang.invoke.MethodType:Class<?> lastParameterType():返回这个方法类型的最后一个参数类型。如果这个方法类型没有参数,则返回空类型作为岗哨值(Sentinel Value)。java.lang.management.RuntimeMXBean:long getPid(): R 返回正在运行的 JVM 的进程 ID 。java.lang.management.ThreadMXBean:ThreadInfo[] dumpAllThreads(boolean, boolean, int): 返回所有活动线程的线程信息,其中有指定的最大元素数量和同步信息的堆栈跟踪。

ThreadInfo[] getThreadInfo(long[], boolean, boolean, int): 返回每个线程的线程信息,这些线程的标识位于输入数组中,其中有指定的最大元素数量和同步信息的堆栈跟踪。

java.lang.reflect.MalformedParameterizedTypeException: 添加了一个新的构造函数,它以字符串的形式作为参数来获取详细信息。

java.net.URLDecoder:java.net.URLEncoder:

java.nio.channels.Channels:

两个新的静态重载方法,允许使用 Charset 的 newReader(ReadByteChannel,Charset)和

newWriter(WriteByteChannel,Charset)。

java.nio.file.FileStore:long getBlockSize(): 在这个文件存储中返回每个块的字节数。

java.time.chrono: 这个包里有三个类,HijrahEra、MiinguoEra 和 ThaiBuddhistEra ,都有同样的方法。

String getDisplayName(TextStyle, Locale): 这将返回用于识别 era 的文本名称,适合于向用户展示。

java.time.format.DateTimeFormatter:localizedBy(Locale): 返回指定格式器的一个副本,其中包含地区、日历、区域、小数和/或时区的本地化值,这将取代该格式器中的值。

java.util: DoubleSummaryStatistics、IntSummaryStatistics 和 LongSummaryStatistics 都有一个新的构造函数,它包含 4 个数值。它使用指定的计数、最小值、最大值和总和构造一个非空实例。

java.util.List:java.util.Map:java.util.Set: 这些接口中的每一个都增加了一个新的静态方法,

copyOf(Collection)。这些函数按照其迭代顺序返回一个不可修改的列表、映射或包含给定集合的元素的集 合。

java.util.Optional:java.util.OptionalDouble:java.util.OptionalInt:java.util.OptionalLong: 每 一 个 类都有一个新的方法,orElseThrow() ,它本质上和 get() 一样,也就是说,如果 Optional 有值则返回。否则, 将抛出 NoSuchElementException 。

java.util.Formatter: java.util.Scanner:

这两个类都有三个新的构造函数,除了其他参数之外,它们都带有一个 charset 参数。

java.util.Properties: 这有一个新的构造函数,它接受一个 int 参数。这将创建一个没有默认值的空属性列表,并且指定初始大小以容纳指定的元素数量,而无需动态调整大小。还有一个新的重载的 replace 方法,接受三个 Object 参数并返回一个布尔值。只有在当前映射到指定值时,才会替换指定键的条目。java.SplittableRandom:

void nextBytes(byte[]): 用生成的伪随机字节填充一个用户提供的字节数组。

java.util.concurrent.FutureTask: 添加了 toString() 方法,该方法返回一个标识 FutureTask 的字符串,以及它的完成状态。在括号中,状态包含如下字符串中的一个,“Completed Normally” 、“Completed

Exceptionally”、 “Cancelled” 或者 “Not completed”。java.util.concurrent.locks.StampedLock:

boolean isLockStamp(long): 返回一个标记戳表示是否持有一个锁。

boolean isOptimisticReadStamp(long): 返回一个标记戳代表是否成功的进行了乐观读(optimistic

read)。

boolean isReadLockStamp(long): 返回一个标记戳表示是否持有一个非独占锁(即 read lock )。

boolean isWriteLockStamp(long): 返回一个标记戳表示是否持有一个独占锁(即 write lock )。

java.jar.JarEntry:

String getRealName(): 返回这个 JarEntry 的真实名称。如果这个 JarEntry 是一个多版本 jar 文件的入口, 它被配置为这样处理,这个方法返回的名字是 JarEntry 所代表的版本条目的入口,而不是

ZipEntry.getName() 返回的基本条目的路径名。如果 JarEntry 不代表一个多版本 jar 文件的版本化条目或者 jar 文件没有被配置为作为一个多版本 jar 文件进行处理,这个方法将返回与 ZipEntry.getName() 返回的相同名称。

java.util.jar.JarFile:

Stream versionedStream(): 返回 jar 文件中指定版本的入口对应 Stream 。与 JarEntry 的 getRealName 方法类似,这与多版本 jar 文件有关。java.util.spi.LocaleNameProvider:getDisplayUnicodeExtensionKey(String, Locale): 为给定的

Unicode 扩展键返回一个本地化名称。

getDisplayUnicodeExtensionType(String, String, Locale): 为给定的 Unicode 扩展键返回一个本地化名称 。 java.util.stream.Collectors:toUnmodifiableList():toUnmodifiableSet():toUnmodifiableMap(Functi on, Function):

toUnmodifiableMap(Function, Function, BinaryOperator): 这四个新方法都返回 Collectors ,将输入元素聚集到适当的不可修改的集合中。

java.lang.model.SourceVersion: 现在有了一个字段,它代表了 JDK 10 的版本。java.lang.model.util.TypeKindVisitor6: javax.lang.model.util.TypeKindVisitor9:

(我必须承认,我从来没听说过这些类)

R visitNoTypeAsModule(NoType, P): 访问一个 MODULE 的 pseudo-type 。我不确定为什么只有这两个类得到这个方法,因为还有 Visitor7 和 Visitor8 变量。javax.remote.management.rmi.RMIConnectorServer:

这个类已经添加了两个字段: CREDENTIALS_FILTER_PATTERN 和 SERIAL_FILTER_PATTERN 。

javax.ButtonModel:看,Swing 还在更新!

ButtonGroup getGroup(): 返回按钮所属的组。通常用于单选按钮,它们在组中是互斥的。

javax.plaf.basic.BasicMenuUI:

Dimension getMinimumSize(JComponent): 返回指定组件适合观感的最小大小。

从整体来看,Java 10似乎并没有包含重大新特性或性能改进。这是可以理解的,毕竟这是新发布周期下的第一个版本。

如上所述,尽管距离 JDK 9 发布仅有六个月的时间,但 JDK 10 实际上有相当多的变化。当然,它们中的一些是非常小的变更,但我认为这表明目前每 6 个月发布一次的节奏,将在 Java 平台快速迭代改进方面起到作用。

同时也让我们期待 JDK 11 将带来些什么…

JDK 11 的页面已经出现了四个 JEP ,包括:动态类文件常量(JEP 309,Dynamic Class-File Constants)、低开销垃圾收集器 Epsilon(JEP 318)、移除 Java EE 和 CORBA 模块(JEP 320),以及 Lambda 参数的本地变量语法

(JEP 323)。JDK 11 计划于 2018 年 9 月发布,并有望成为新的 LTS 版本。

原文发布于微信公众号 - 程序员阿凯(AKBC159)

原文发表时间:2018-04-08

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏SeanCheney的专栏

《Python分布式计算》第2章 异步编程 (Distributed Computing with Python)协程一个异步实例总结

从本章开始,终于开始写代码了!本书中所有的代码都适用于Python 3.5及以上版本。当模块、语句或语法结构不适用于以前的版本时(比如Python 2.7),会...

38010
来自专栏开发 & 算法杂谈

Zookeeper C API学习总结

客户端使用C语言开发,zookeeper提供了两个库,zookeeper_st(单线程库)以及zookeeper_mt(多线程库)。

3315
来自专栏大内老A

我的WCF之旅(4):WCF中的序列化[上篇]

SOA 和Message Windows Communication Foundation (WCF) 是基于面向服务架构(Service Orienta...

18510
来自专栏编舟记

Clojure集合管道函数练习

TDD讨论组里的申导最近在B站直播了Martin Fowler的经典文章Refactoring with Loops and Collection Pipeli...

902
来自专栏跟着阿笨一起玩NET

分表处理设计思想和实现[转载]

分表是个目前算是比较炒的比较流行的概念,特别是在大负载的情况下,分表是一个良好分散数据库压力的好方法。

611
来自专栏转载gongluck的CSDN博客

黑暗的内存管理

黑暗的内存管理 很多人对 C 语言深恶痛绝,仅仅是因为 C 语言迫使他们在编程中必须手动分配与释放内存,然后通过指针去访问,稍有不慎可能就会导...

3526
来自专栏杨建荣的学习笔记

关于enq: TX - allocate ITL entry的问题分析(r3笔记第66天)

今天发现系统在下午1点左右的时候负载比较高,就抓取了一个最新的awr报告. Snap IdSnap TimeSessionsCursors/SessionB...

3136
来自专栏互联网高可用架构

白话阿里巴巴Java开发手册(编程规约)

1723
来自专栏大内老A

ASP.NET Core中的依赖注入(5): ServiceProvider实现揭秘 【解读ServiceCallSite 】

通过上一篇的介绍我们应该对实现在ServiceProvider的总体设计有了一个大致的了解,但是我们刻意回避一个重要的话题,即服务实例最终究竟是采用何种方式提供...

18510
来自专栏MYSQL轻松学

MySQL系列优化(一)

MYSQL优化是一个非常大的课题,这篇文章主要介绍了跟MYSQL相关的4个方面,如果想深入研究可以查下相关资料。 ---- 一、服务器级别优化 二、操作系统级别...

2755

扫码关注云+社区