Victor's Code Journey
Victor's Code Journey

Java 模块化

JDK 从Java 9开始 在包之上引入了一个新的抽象级别,正式名称为 Java 平台模块系统 (JPMS),简称“模块”。Java 模块是一种打包机制,使您能够将 Java 应用程序或 Java API 打包为单独的 Java 模块。Java 模块被打包为模块化 JAR 文件。Java 模块可以指定它包含哪些 Java 包,这些包应该对使用此模块的其他 Java 模块可见。Java 模块还必须指定完成其工作所需的其他 Java 模块。

Spring Transactional

Spring @Transactional的配置方式有两种:

  1. xml配置文件中,添加事务管理器bean配置
<!-- 事务管理器配置,单数据源事务 -->
    <bean id="myTransactionManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="myDataSource" />
    </bean>
<!-- 使用annotation定义事务 -->
    <tx:annotation-driven transaction-manager="myTransactionManager" />
  1. 在使用事务的方法或者类上添加 @Transactional("myTransactionManager")注解.
  • 标注在类前:标示类中所有方法都进行事务处理
  • 标注在接口、实现类的方法前:标示方法进行事务处理

Java并发之CompletableFuture

Future接口可以构建异步应用,但依然有其局限性。它很难直接表述多个Future 结果之间的依赖性。实际开发中,我们经常需要达成以下目的:

  • 将两个异步计算合并为一个——这两个异步计算之间相互独立,同时第二个又依赖于第一个的结果。
  • 等待 Future 集合中的所有任务都完成。
  • 仅等待 Future集合中最快结束的任务完成(有可能因为它们试图通过不同的方式计算同一个值),并返回它的结果。
  • 通过编程方式完成一个Future任务的执行(即以手工设定异步操作结果的方式)。
  • 应对 Future 的完成事件(即当 Future 的完成事件发生时会收到通知,并能使用 Future 计算的结果进行下一步的操作,不只是简单地阻塞等待操作的结果)

Java并发之原子变量Atomic

Java从JDK1.5开始提供了java.util.concurrent.atomic包,方便程序员在多线程环境下,无锁的进行原子操作。原子变量的底层使用了处理器提供的原子指令,但是不同的CPU架构可能提供的原子指令不一样,也有可能需要某种形式的内部锁,所以该方法不能绝对保证线程不被阻塞。

CPU Memory Cache

曾今计算机稳定的基本结构悄然改变,硬件开发人员开始致力于优化单个子系统。于是电脑一些组件的性能大大的落后因而成为了瓶颈。由于开销的原因,大容量存储器和内存子系统相对于其他组件来说改善得更为缓慢。

大容量存储的性能问题往往靠软件来改善: 操作系统将常用(且最有可能被用)的数据放在主存中,因为后者的速度要快上几个数量级。或者将缓存加入存储设备中,这样就可以在不修改操作系统的前提下提升性能。(然而,为了在使用缓存时保证数据的完整性,仍然要作出一些修改).

而解决内存的瓶颈更为困难,它与大容量存储不同,几乎每种方案都需要对硬件作出修改。目前,这些变更主要有以下这些方式:

  • RAM的硬件设计(速度与并发度)
  • 内存控制器的设计
  • CPU缓存
  • 设备的直接内存访问(DMA)

java:随机数

计算机科学中的随机数分为两种:

  • 真随机数: 其生成过程是不可预测、不可重复的,完全基于自然界中物理过程的随机性。
  • 伪随机数: 其生成过程是确定性的、可预测的,但通过一个算法使得生成的数字序列看起来像是随机的。
    • 使用一个确定的数学公式。它从一个初始值(称为“种子”)开始,通过算法计算出下一个数,然后用这个数作为新的内部状态,继续计算下一个数,如此反复。

Java并发之并发优先线程池

Java原生线程池在提交任务时会优先将线程数扩展到 CoreSize,然后会将任务入队,在队列塞满后会尝试继续扩展线程数到MaxSize。这种方式适合cpu密集型任务,而且任务时间不宜过长,否则会造成队列里面任务的堆积。

对于 RPC 通信场景的 IO 密集型任务,这种调度方式就不太合适。更适合并发优先的调度策略,即优先扩展线程数到 MaxSize。然后再尝试入队。要是实现上面的调度策略需要基于 JDK 原生线程池做一下调整。

Java并发之线程池-ThreadPoolExecutor

Eexecutor作为灵活且强大的异步执行框架,其支持多种不同类型的任务执行策略,提供了一种标准的方法将任务的提交过程和执行过程解耦开发,基于生产者-消费者模式,其提交任务的线程相当于生产者,执行任务的线程相当于消费者,并用Runnable来表示任务,Executor的实现还提供了对生命周期的支持,以及统计信息收集,应用程序管理机制和性能监视等机制。

classDiagram
    class ScheduledThreadPoolExecutor
    ScheduledThreadPoolExecutor--|>ThreadPoolExecutor
    ScheduledThreadPoolExecutor..|>ScheduledExecutorService
    class ThreadPoolExecutor
    ThreadPoolExecutor--|>AbstractExecutorService
    class ForkJoinPool
    ForkJoinPool--|>AbstractExecutorService
    class AbstractExecutorService
    <<abstract>> AbstractExecutorService
    AbstractExecutorService..|>ExecutorService
    ScheduledExecutorService..|>ExecutorService
    class ScheduledExecutorService
    <<interface>> ScheduledExecutorService
     class ExecutorService
    <<interface>> ExecutorService
    ExecutorService..|>Executor
    class Executor
    <<interface>> Executor

Java并发之Lock原理解析

同步器是实现锁的关键,利用同步器将锁的语义实现,然后在锁的实现中聚合同步器。可以这样理解:锁的API是面向使用者的,它定义了与锁交互的公共行为,而每个锁需要完成特定的操作也是透过这些行为来完成的(比如:可以允许两个线程进行加锁,排除两个以上的线程),但是实现是依托给同步器来完成;同步器面向的是线程访问和资源控制,它定义了线程对资源是否能够获取以及线程的排队等操作。锁和同步器很好的隔离了二者所需要关注的领域,严格意义上讲,同步器可以适用于除了锁以外的其他同步设施上(包括锁)。

AbstractQueuedSynchronizer提供了一个基于FIFO队列,可以用于构建锁或者其他相关同步装置(Lock, Semaphore, Latch, Barrier)的基础框架。AbstractQueuedSynchronizer的子类推荐作为为自定义同步装置的内部类,同步器自身没有实现任何同步接口,它仅仅是定义了若干acquire之类的方法来供使用。该同步器即可以作为互斥模式也可以作为共享模式,当它被定义为一个互斥模式时,其他线程对其的获取就被阻止,而共享模式对于多个线程获取都可以成功。