JDK9干货

JDK 9正处于开发的最后阶段, 向着9月21号的发布目标冲刺。Java 平台模块系统的公开评审投票基本上被一致通过,所以目前一切都可以回归正常了。

你可在此处下载 OpenJDK 9:http://zulu.org/zulu-9-pre-release-downloads/ (尝鲜版)。

1. 标识符. JEP 213, Milling Project Coin 带来了一些变化,希望这些不会影响到太多的人。


早些版本的Java,可以使用一个下划线来作为标识符,虽然不被建议这样使用,但是确实可以使用单个下划线作为一个变量名。在 JDK9 中,单个下划线变成了一个关键字。这可能听起来和奇怪,但是最简单的方式就是不使用单个下划线作为标识符。可能将来在 JDK10 中,单个下划线只能用于 lambda 表达式的标识符。这样将使 lambda 表达式可以使用单个参数,从而使主体语法更清晰(例如: _ -> foo())


2. JDK 的布局发生了变化 (JEP 220): 如果你依赖于 $ JAVA_HOME 中特定的文件,你可能需要做一些更改。


具体需要的更改如下:

  • 不再有单独的 jre,bin,lib 等子目录。 JDK 目录结构现在与单个 bin 目录平行(因此只有一个 Java 可执行文件的副本),lib 目录用于本机库和 JDK 模块的 jmods 目录。还有一个新的 conf 目录,可以让管理员更改 JDK 配置。Conf 中有网络和日志属性。

  • 这个转变意味着不再有 rt.jar 或 tools.jar 文件。你需要更改代码来访问这些文件。

  • hprof 代理已从JDK 9(JEP 240)中删除,因此 lib / libhprof.so(或 Windows 上的 bin / hprof.dll )文件也被删除。


3. JDK 版本字符串(JEP 223):老的定义 JDK 版本的方法相当混乱。例如,我们有 JDK 8u131 ,但是如果你运行 java -version ,你会得到 java version "1.8.0_131" 。


为了从人类和应用程序角度简化这个(定义版本的方法),现在的版本格式是 JDK $MAJOR.$MINOR.$SECURITY.$PATCH ,所以在 JDK9 上的 java -version 将返回 java version "9"(一旦发布最终的 release 版,我们获取更新之后该版本号就会改动)。这里重要的是,如果你在代码中使用 JVM 的版本字符串,并依赖于当前版本格式,那么在 JDK 9 中你必须进行代码改动才能正确运行。


4. Thread.stop(Throwable) 现在会抛出一个 UnsupportedOperationException ,它之前并没有抛出类似异常。


由于其自身缺乏线程安全性,因此不推荐使用此方法。另一个不带参数的 Thread.stop() 版本仍然可以使用,并且不会抛出异常(但仍然不推荐使用,并强烈建议不要使用此函数)


5. Java 网络登录协议(Java Network Launch Protocol ,JNLP)已更新,以支持严格的配置文件解析。现在使用的格式符合 XML 规范,要求“&”版本范围连接器表示为“&”。


配置解析目前是严格的,这意味着一些在旧版本的 Java 中可以使用的文件现在将会产生错误。 有关更多详细信息,请参见JSR 52维护页面


6. 与 JPMS 相关的扩展机制(可选软件包)和已批准的标准覆盖机制都已被删除,并使用 JPMS 对应物替代。


因此,$JAVA_HOME/lib/ext 和 $JAVA_HOME/lib/endorsed 的目录已被删除。如果你重新创建这些目录,并尝试把东西放在这些目录下,祈祷他们能工作,这是不可能的。JVM 在查找到这些目录时将无法启动,你将收到以下错误消息:

/lib/ext exists, extensions mechanism no longer supported; Use -classpath instead.
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.


7. 六个之前已弃用的公共方法已经被删除。这是一件相当大的事情,因为这些是 Java 历史上第一次要删除的API。


已删除的方法包括java.util.jar.Pack200,java.util.jar.Unpack200中的addPropertyChangeListener()、removePropertyChangeListener(),以及 java.util.logging.LogManager类。


8.作为Java Authentication and Authorization Service (JAAS,Java授权认证服务)的一部分的com.sun.security.auth.callback.DialogCallbackHandler 类已被删除。


它在 JDK 8 中就已被弃用。


9. JRE 版本选择将不再可用。过去有两种做法可以实现 JRE 版本选择。第一个是在命令行中使用 -version: 选项。


如果使用该选项,JVM 将中止而不再启动。第二种方式是从 jar 文件的 manifest 。在这种情况下,JDK 9 将忽略该指令,但会正常启动。有人觉得,与改变命令行相比,强迫人们改变 manifest 太麻烦了。请注意,-version 选项(不带后面的冒号和版本号)仍然可以报告你所使用的 Java 运行时版本。


10. 废弃的GC选项已被移除(JEP 214)。 在 JDK 8(JEP 173)中已经弃用了一些详细的 GC 选项和选项组合。


这些将不会被识别,并将导致 JVM 在启动时中止。要注意的选项如下所示

-XX:-UseParNewGC -XX:+UseConcMarkSweepGC
-XX:+UseParNewGC
-Xincgc
-XX:+CMSIncrementalMode -XX:+UseConcMarkSweepGC
-XX:+CMSIncrementalMode -XX:+UseConcMarkSweepGC -XX:-UseParNewGC
-XX:+UseCMSCompactAtFullCollection
-XX:+CMSFullGCsBeforeCompaction
-XX:+UseCMSCollectionPassing

在 JDK 9 中,concurrent-mark-sweep (iCMS) 的增量模式已被移除,目前的计划是在 JDK 10 中完全删除 CMS 。

命令行选项

这对我来说似乎是一个很大的变化,但到目前为止,我还没有看到它被突出强调过(或有良好的记录文档)。

除了上述 GC 选项之外,在 JVM 如何处理日志记录中有重大改动。JEP 158 引入了统一日志记录系统,并且该系统被用在 GC 日志中,用于提供统一的 GC 日志记录(JEP 271)。这会影响许多常用的 GC 日志记录命令行选项以及其他一些操作。

为了弄清楚发生了什么改动,我从 OpenJDK 源代码(特别是 src/share/vm/runtime/globals.hpp 文件)中提取了相关的行。通过做 diff ,我能够得到所有从 JDK 8 中删除的 -XX 选项以及已添加到 JDK 9 中的所有 -XX 选项的列表。然后,我写了一个脚本,使用一个简单的应用程序依次查看使用在 JDK 8 中支持但在 JDK 9 中已删除的选项的结果。

对 -XX 选项的更改可以分为三组:

已忽略的命令行选项

如果使用其中的一个,您将收到以下警告消息,但 JVM 将正常启动。

Java HotSpot(TM) 64-Bit Server VM warning: Ignoring option <Option>; support was removed in 9.0

  • AdaptiveSizePausePolicy (自适应大小暂停策略)

  • CodeCacheMinimumFreeSpace(代码缓存最小空闲空间)

  • DefaultThreadPriority(默认线程优先级)

  • JNIDetachReleasesMonitors(JNI分离释放监视器)

  • LazyBootClassLoader(惰性类启动器)

  • NmethodSweepCheckInterval(N方法扫描检查间隔)

  • NmethodSweepFraction(N方法扫描片段)

  • PrintOopAddress(打印OOP地址)

  • ReflectionWrapResolutionErrors(反射包装处理错误)

  • StarvationMonitorInterval(饥饿监视间隔)

  • ThreadSafetyMargin(线程安全边界)

  • UseAltSigs(使用alt信号)

  • UseBoundThreads(使用绑定线程)

  • UseCompilerSafepoints(使用编译器安全点)

  • UseFastAccessorMethods(使用快速访问方法)

  • UseFastEmptyMethods(使用快速空方法)

  • BackEdgeThreshold(后边缘阈值)

  • PreInflateSpin(预浸旋转)

已弃用的命令行选项

这些选项将在 JVM 启动时触发警告,或者告诉你 JVM 将使用哪个选项,或者告诉你应该使用哪个选项。其中大部分与统一的 GC 日志有关。

以下是两个关于警告信息的示例:

warning][gc] -XX:+PrintGC is deprecated. Will use -Xlog:gc instead.

Java HotSpot(TM) 64-Bit Server VM warning: Option CreateMinidumpOnCrash was deprecated in version 9.0 and will likely be removed in a future release. Use option CreateCoredumpOnCrash instead.

下表给出了 JDK 8 中的命令行选项及其在 JDK 9 中对应的替换选项。

不再生效的选项

这些是涉及兼容性的最重要的选项。如果你以前使用过这些命令,并且在不更改命令行情况下,那么你的应用程序将无法启动。当你使用其中之一时,你将收到以下错误消息:

Unrecognized VM option '<Option>'
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.

以下是在 JDK 9 中不再工作的 50 个选项列表。检查下你是否在命令行和启动脚本中使用了这些选项。

  • AdjustConcurrency

  • CMSCompactWhenClearAllSoftRefs

  • CMSDumpAtPromotionFailure

  • CMSFullGCsBeforeCompaction

  • CMSIncrementalDutyCycle

  • CMSIncrementalDutyCycleMin

  • CMSIncrementalMode

  • CMSIncrementalOffset

  • CMSIncrementalPacing

  • CMSParPromoteBlocksToClaim

  • CMSPrintEdenSurvivorChunks

  • CollectGen0First

  • GCLogFileSize

  • NumberOfGCLogFiles

  • ParallelGCVerbose

  • PrintAdaptiveSizePolicy

  • PrintCMSInitiationStatistics

  • PrintCMSStatistics

  • PrintClassHistogramAfterFullGC

  • PrintClassHistogramBeforeFullGC

  • PrintFLSCensus

  • PrintFLSStatistics

  • PrintGCApplicationConcurrentTime

  • PrintGCApplicationStoppedTime

  • PrintGCCause

  • PrintGCDateStamps

  • PrintGCTaskTimeStamps

  • PrintGCTimeStamps

  • PrintHeapAtGC

  • PrintHeapAtGCExtended

  • PrintJNIGCStalls

  • PrintOldPLAB

  • PrintPLAB

  • PrintParallelOldGCPhaseTimes

  • PrintPromotionFailure

  • PrintReferenceGC

  • PrintTLAB

  • PrintTenuringDistribution

  • TraceDynamicGCThreads

  • TraceGen0Time

  • TraceGen1Time

  • TraceMetadataHumongousAllocation

  • TraceParallelOldGCTasks

  • UseCMSCollectionPassing

  • UseCMSCompactAtFullCollection

  • UseGCLogFileRotation

  • UseMemSetInBOT

  • UsePPCLWSYNC

  • UseVMInterruptibleIO

  • WorkAroundNPTLTimedWaitHang

希望在你移植到 JDK 9 之时,这可以帮助你检查是否需要对应用程序及其配置进行更改。

### Java多线程技术的实现方式与并发控制的最佳实践 #### 1. 多线程的实现方式 Java提供了多种实现多线程的方式,主要包括继承`Thread`类和实现`Runnable`接口两种基本方法。通过这两种方式,开发者可以定义线程的行为逻辑。 - **继承 Thread 类** 继承`Thread`类并通过重写`run()`方法来定义线程的任务逻辑[^1]。这种方式简单直观,但由于Java不支持多重继承,因此可能会限制程序设计的灵活性。 - **实现 Runnable 接口** 更推荐的方式是实现`Runnable`接口,因为这不会占用类唯一的继承机会,适合复杂的面向对象设计场景[^2]。 ```java class MyRunnable implements Runnable { @Override public void run() { System.out.println("Running in a separate thread."); } } public class Main { public static void main(String[] args) { new Thread(new MyRunnable()).start(); } } ``` #### 2. 并发控制的方法 在多线程环境中,多个线程可能同时访问共享资源,从而引发数据竞争或一致性问题。以下是几种常用的并发控制手段: - **Synchronized 关键字** `synchronized`用于确保同一时间只有一个线程能进入被标记的方法或代码块,有效防止竞态条件。它可以通过修饰实例方法、静态方法或者作为代码块使用。 ```java public synchronized void criticalSection() { // 只有一个线程可执行此部分 } ``` - **Lock 接口及其子类** 相较于`synchronized`,`Lock`接口提供更灵活的功能,比如尝试锁定(`tryLock`)、定时等待锁释放等操作[^3]。常用的是`ReentrantLock`,允许同一线程多次获取相同的锁而不死锁。 ```java import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class Counter { private int count = 0; private final Lock lock = new ReentrantLock(); public void increment() { lock.lock(); // 获取锁 try { count++; } finally { lock.unlock(); // 确保最终解锁 } } } ``` - **原子变量 (Atomic Variables)** 利用`java.util.concurrent.atomic`包下的类(如`AtomicInteger`, `AtomicLong`),可以在无需显式加锁的情况下完成一些简单的更新操作,提高性能的同时减少死锁风险[^4]。 ```java import java.util.concurrent.atomic.AtomicInteger; public class AtomicCounter { private AtomicInteger count = new AtomicInteger(0); public void increment() { count.incrementAndGet(); // 原子化增加 } public int getCount() { return count.get(); } } ``` #### 3. 最佳实践建议 为了构建高效稳定的多线程应用,遵循以下几点最佳实践至关重要: - **优先考虑高级抽象工具** 尽量利用JDK内置的并发工具库,例如`ExecutorService`代替手动管理线程池,简化开发流程并降低错误率[^4]。 - **避免过度依赖全局锁** 过度使用单一锁可能导致严重的瓶颈效应;应根据实际需求划分细粒度锁区域[^5]。 - **合理规划线程数量** 创建过多线程会消耗大量内存空间,并带来上下文切换成本;反之不足则无法充分利用硬件资源。通常依据CPU核心数设定合理的线程上限是一个不错的选择。 - **测试与调试相结合** 鉴于多线程程序固有的不确定性特征,在正式部署前务必进行全面的压力测试验证其健壮性和稳定性[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值