`

读书笔记:《分布式JAVA应用 基础与实践》 第四章 分布式JAVA应用与JDK类库

阅读更多

4.1 集合包

ArrayList, LinkedList,Vector,TreeSet,HashMap,TreeMap 等,无需多说

 

4.2 并发包 (java.util.concurrent)

4.2.1 ConcurrentHashMap

线程安全的 HashMap 实现,主要原理是将集合分成多个段 ( 默认 16 ) ,分段加锁,实现高并发。

据作者的测试结果,在线程数较少时,无论元素数量多少, ConcurrentHashMap 带来的性能提升不明显,但在线程数为 50 以上时, ConcurrentHashMap 在增加和删除时性能提升了一倍左右,查找时性能提升了 10 倍左右。

因而,在并发场景, ConcurrentHashMap 较之 HashMap 是更好的选择

4.2.2 CopyOnWriteArrayList

    线程安全的 ArrayList, 基于 ReentrantLock 保证增加元素和删除元素动作的互斥,在读操作时无锁。

据作者的测试结果,随着元素数量和线程数量增加, CopyOnWriteArrayList 在增加元素和删除元素时性能下降明显,比 ArrayList 更低。但在查找元素上却比 ArrayList 好很多(大于 10 倍)。

因此,在读多写少的并发场景, CopyOnWriteArrayList 较之 ArrayList 是更好的选择。

4.2.3 CopyOnWriteArraySet

基于 CopyOnWriteArrayList 实现,唯一不同的是每次 add 时调用的是 addIfAbsent 方法,此方法需遍历当前 Object 数组,检查待增加的元素是否已存在,已存在则直接返回。故性能略低于 CopyOnWriteArrayList

4.2.4 ArrayBlockingQueue

一个基于固定大小数组、 ReentrantLock 以及 Condition 实现的可阻塞的先进先出的 Queue.

类似的还有过 LinkedBlockingQueue, put offer 采用一把锁,对 take poll 采用另一把锁,避免了读写时互相竞争锁的现象,因此,在高并发读写操作都多的情况下,性能会较 ArrayBlockingQueue 好很多

4.2.5 AtomicInteger

一个支持原子操作的 Integer 类,在没有 AtomicInteger 前,要实现一个按顺序获取的 ID ,就必须在每次获取时进行加锁操作,以避免出现并发时获取到同样 ID 的现象。借助 AtomicInteger ,则可以更简易地实现,如下:

Private static AtomicInteger counter = new AtomicInteger();

Public static int getNextId() {

       Return counter.incrementAndGet();

}

incrementAndGet 方法基于 CPU CAS 原语实现,基于 CAS 的操作可以认为是无阻塞的,因此性能好于同步锁的方式。

对于使用 JDK5 以上的版本时,应尽量使用 atomic 的类,除 AtomicInteger 外,还有 AtomicLong AtomicBoolean AtomicReference 等。

4.2.6 ThreadPoolExecutor

一个高效的、支持并发的线程池,要想用好这个线程池,需要合理配置 corePoolSize, 最大线程数、任务缓冲的队列,以及线程池满时的处理策略。常见的需要有如下两种

1.       高性能

如果希望高性能地执行 Runnable 任务,即当线程池中的线程数尚未达到最大个数,则立刻交给线程执行或在最大线程数量的保护下创建线程来执行,可选的方式为使用 SynchronousQueue 作为任务的队列。

2.       缓冲执行

如果希望 Runnable 任务尽量被 corePoolSize 范围的线程执行掉,可选的方式为使用 ArrayBlockingQueue LinkedBlockQueue 作为任务缓冲的队列。这样,当线程数等于或超过 corePoolSize 后,会先加入缓冲队列中,而不是直接交由线程执行。

4.2.7 Executors

       提供一些方便创建 ThreadPoolExecutor 的方式

1.       newFixedThreadPool(int)

创建固定大小的线程池 keepAliveTime 0 ,即线程启动后就不退出,缓冲队列为 LinkedBlockingQueue, 大小为整型的最大数

2.       newSingleThreadExecutor()

创建大小为 1 的固定线程池

3.       newCachedThreadPool()

创建 corePoolSize 0 最大线程数为整型的最大数,线程 keepAliveTime 1 分钟,缓存任务的队列为 SynchronousQueue 的线程池

4.       newSheduledThreadPool(ing)

创建 corePoolSize 为传入参数,最大线程数为整型的最大数,线程 keepAliveTime 0, 缓存任务的队列为 DelayedWorkQueue 的线程池。在实际业务中,通常会有一些需要定时或延迟执行的任务,更典型的是在异步操作时需要超时回调的场景。

JDK5 之前,用 Timer 实现这个功能,两者区别:

1.       Timer 单线程,一旦一个 task 运行缓慢,其它的 task 也会推迟, ScheduledThreadPool 并发

2.       Timer 中的 task 抛出 RunntimeException 时,其它 task 也不会执行

3.       ScheduledThreadPool 可以执行 callable task

4.2.8          FutureTask

可用于异步获取执行结果或取消执行任务的场景,通过传入 Runnable Callable 的任务给 FutureTask ,直接调用其 run 方法或放入线程池执行,之后可在外部通过 FutureTask get 异步获取执行结果。 FutureTask 可以确保即使调用了多闪 run 方法,它都会只执行一次 Runnable Callable 任务。

4.2.9          Semaphore

用于控制某资源同时被访问的个数的类,例如连接池中控制创建的连接个数。

 

4.2.10      CountDownLatch

可用于控制多个线程同时开始某动作的类,采用的方式为减计数方式。当计数减至零时,位于 latch.await 后的代码才会被执行。

4.2.11      CyclicBarrier

CountDownLatch 不同, CyclicBarrier 是当 await 数量达到设定的数量后,才继续向下执行。

4.2.12      ReentrantLock

一个更为方便的控制并发资源的类,和 synchronized 语法达到的效果是一致的。这两者之间如何取舍呢,借用 Brian Goetz 的话 (http://www.ibm.com/developerworks/cn/java/j-jtp10264/index.html)

答案非常简单 —— 在确实需要一些 synchronized 所没有的特性的时候,比如时间锁等候、可中断锁等候、无块结构锁、多个条件变量或者锁投票。 ReentrantLock 还具有可伸缩性的好处,应当在高度争用的情况下使用它,但是请记住,大多数 synchronized 块几乎从来没有出现过争用,所以可以把高度争用放在一边。我建议用 synchronized 开发,直到确实证明 synchronized 不合适,而不要仅仅是假设如果使用 ReentrantLock 性能会更好 。请记住,这些是供高级用户使用的高级工具。(而且,真正的高级用户喜欢选择能够找到的最简单工具,直到他们认为简单的工具不适用为止。)。一如既往,首先要把事情做好,然后再考虑是不是有必要做得更快。

4.2.13      Condition

接口,典型实现 ReentrantLock ReentrantLock 提供了一个 newCondition 方法,以便用户在同一个锁的情况下可以根据不同的情况执行等待或唤醒动作。

ReentrantLock.newCondition().await()

ReentrantLock..newCondition().signal()

4.2.14      RenentrantReadWriteLock

ReentrantLock 没有继承关系,它提供了读锁( ReadLock )和写锁( WriteLock ),比 ReentrantLock 的一把锁,读写锁分离对读多写少的情况,提高性能。

当调用读锁的 lock 方法时,没有线程持有写锁,就可获得读锁,意味着只要进行读操作,就没有其它线程进行写操作,读操作时无阻塞的;

当调用写锁的 lock 时,如果此时没有线程持有读锁或写锁,则可继续,意味着要进行写时,如果有其它线程进行读或写,就会被阻塞,

读写锁使用时的升级和降级机制:

同一线程中,持有读锁后,不能直接调用写锁的 lock

同一线程中,持有写锁后,可调用读锁的 lock 方法,之后如果调用写锁的 unlock 方法,那么当前锁将降级为读锁。

 

记作者的测试: 同时启动 102 个线程, 100 个进行读操作 (HashMap.get) 2 个进行写操作 (HashMap.put), 较之 ReentrantLock ReentrantReadWriteLock 性能提升了三倍多。

 

以上分析了 JDK5 以后版本提供的并发包中一些常用类的实现方法,这些类能够帮助开发者更好地控制高并发下的资源操作,尽可能地避免出现不一致及资源竞争激烈等现象。总的来说,基于 CAS 、拆分锁、 voliate AbstractueuedSynchronier 是这些类的主要实现方法,这些方法都是为了尽量减少高并发时的竞争现象,对于实际编码有一定的参考价值,从而保障程序即使在 高并发时也能保持较高的性能。

 

 

 

 

 

 

 

 

 

分享到:
评论

相关推荐

    Java+JDK6学习笔记(PDF版书籍,免费下载)

    ### Java+JDK6学习笔记知识点详解 #### 一、Java简介 - **起源与历史:** - 最初由Sun公司的Green Project发起,旨在创建一个名为Star7的应用程序编程语言。 - 名称来源于创始人James Gosling窗外的一棵橡树...

    达内java学习基础笔记整理

    1.2 Java的特点:Java语言具有平台无关性、面向对象、分布式处理、多线程支持、动态加载类库、安全性高、可移植性强等特点。 1.3 Java开发环境:Java开发环境包括Java Development Kit(JDK)、Integrated ...

    java基础整理笔记超详细

    【Java基础整理笔记超详细】 Java是一门广泛使用的高级编程语言,由Sun Microsystems(后被Oracle收购)在1995年推出。它的设计目标是跨平台、面向对象,并且具有健壮性和安全性。Java这个名字源于印度尼西亚的咖啡...

    Java学习笔记,Java基础篇

    3. 分布式:Java 语言支持 Internet 应用程序的开发,具有很强的分布式特性。 4. 动态绑定:Java 语言全面支持动态绑定,而 C++ 语言只对虚函数使用动态绑定。 Java 语言的应用领域非常广泛,包括: 1. 个人计算机...

    Java JDK 6.0 学习笔记.pdf

    Java JDK(Java Development Kit)是Java编程语言的核心组件,包含Java运行环境、编译器、类库以及各种工具,是开发者进行Java程序开发的基础。Java JDK 6.0是Oracle公司发布的一个重要版本,提供了许多新的特性和...

    毕向东Java笔记

    - **分布式**:Java内置对网络的支持,方便开发分布式应用。 - **动态性**:Java具有良好的动态性,能够适应不断变化的环境。 - **多线程**:Java提供内置多线程支持,简化并发编程。 - **安全性**:Java具有...

    毕向东Java基础视频教程笔记

    毕向东的Java基础视频教程笔记为我们提供了一个学习Java基础知识的宝贵资源。在这个笔记中,我们主要讨论以下几个核心概念: 1. **Java平台的三个版本**: - Java SE (Standard Edition):适用于桌面应用程序和...

    Java JDK 6学习笔记——ppt简体版

    10. **JNDI与JMS**:Java Naming and Directory Interface(JNDI)用于查找和绑定分布式系统中的资源,Java Message Service(JMS)则是Java消息传递的标准。这两个技术在企业级应用中广泛使用。 通过这份Java JDK ...

    JAVA程序设计学习笔记.pdf

    JAVA 系统一般包含四个部分:JAVA 环境、JAVA 语言、JAVA API 应用程序接口、JAVA 类别库。JDK 是 JAVA Developer's Kit 的简称,意即 JAVA 的开发工具。JAVA 2 SDK 开发工具可从 SUN 公司网站下载,包含这四个部分...

    JAVA基础笔记第一次

    JRE是运行Java应用程序所需的基本环境,由JVM(Java虚拟机)和核心类库组成。而JDK则在此基础上增加了开发工具,如编译器javac等。 安装JDK后,可以通过图形界面或命令行与系统交互。在Windows系统中,可以使用Win+...

    Java基础笔记MarkDown版4万字肝吐血

    - **JDK**(Java Development Kit):Java开发工具包,包括Java编译器、文档、示例代码和工具,以及JRE,是Java开发环境的基础。 - **JVM**(Java Virtual Machine):Java虚拟机,负责执行Java字节码,提供了一个...

    Java帮助文档大全

    1. **Java Development Kit (JDK)**:开发Java应用程序所需的工具集合,包括编译器(javac)、解释器(java)、jar打包工具等。 2. **Java Class Library**:提供大量预定义类和接口,如集合框架、I/O流、网络编程、...

    《Java JDK6学习笔记》(中文ppt->pdf)

    - **起源与发展**:Java 最初由 Sun Microsystems 的 James Gosling 在 Green Project 中开发,初衷是为了创建一个名为 Star7 的应用程序。其命名灵感来源于 Gosling 办公室外的一棵橡树(Oak)。随着全球互联网的...

    java基础学习笔记

    1. **JDK与SDK**:Java Development Kit (JDK) 是Java开发的基础,包含了编译器、JRE(Java Runtime Environment)以及一系列工具,如Javadoc和JAR。Software Development Kit (SDK) 是一个更广泛的术语,通常包括...

    传智播客Java_SE基础毕向东老师全程笔记

    ### 第四章:异常机制 - 异常处理机制:捕获、抛出、try-catch-finally语句。 - 自定义异常类的创建。 - 常用异常类:如`IOException`、`NullPointerException`等。 ### 第五章:多线程技术 - 线程的概念与特点。...

    Java面试进阶解析笔记.pdf

    6. 分布式:Java提供了丰富的网络API,支持Internet应用开发,可以轻松实现分布式计算和数据共享。 7. 健壮性:Java的强类型检查、异常处理和垃圾回收机制增强了程序的稳定性和可靠性。 8. 高性能:虽然Java最初是...

    JAVA_SE毕向东 笔记

    - 分布式:Java提供内置的支持用于创建分布式应用。 - 动态性:Java支持运行时的类装载、动态链接等特性。 - 多线程:Java提供内置的多线程支持,方便开发复杂的并发程序。 - 安全性:Java具有强大的安全特性,...

    毕向东_Java基础课堂笔记.pdf

    - **分布式**:Java天生支持网络计算,易于实现客户端与服务器之间的通信。 - **动态性**:Java语言支持动态链接,即可以在运行时动态加载类库。 - **多线程**:Java内置了对多线程的支持,便于开发高并发应用。 ...

    java基础相关学习笔记

    - **简单性**:Java设计者的目标之一是使它易于学习和使用。它采用了C++的部分语法,但去除了许多容易引起错误的特性,如指针。同时,Java引入了自动内存管理,即垃圾回收机制,减轻了程序员管理内存的负担。 - **...

    java基础笔记

    4. **类与对象**:Java是面向对象的语言,一切皆为对象。类是对象的蓝图,包含属性(字段)和行为(方法)。对象则是类的实例,通过构造函数创建。 5. **封装、继承和多态**:封装是隐藏实现细节,提供公共接口;...

Global site tag (gtag.js) - Google Analytics