`
coolxing
  • 浏览: 874162 次
  • 性别: Icon_minigender_1
  • 来自: 北京
博客专栏
9a45b66b-c585-3a35-8680-2e466b75e3f8
Java Concurre...
浏览量:97280
社区版块
存档分类
最新评论

ConcurrentHashMap和CopyOnWriteArrayList--Java Concurrency In Practice C05读书笔记

阅读更多

[本文是我对Java Concurrency In Practice 5.2的归纳和总结.  转载请注明作者和出处,  如有谬误, 欢迎在评论中指正. ]

ConcurrentHashMap类

我们可以使用Collections.synchronizedMap()方法包装HashMap得到线程安全的Map, 但是如前所述, 这样会带来很大的性能损失. JDK5之后我们有了新的选择--ConcurrentHashMap. ConcurrentHashMap具有如下特点:

1. ConcurrentHashMap具有更好的并发性能. ConcurrentHashMap是线程安全的, 但是其同步策略和SynchronizedMap有很大不同. ConcurrentHashMap在read时几乎不用加锁, 而write时使用的是细粒度的分段锁, ConcurrentHashMap甚至可以做到并发write. 

2. 由于ConcurrentHashMap的分段加锁机制, 使用ConcurrentHashMap类时, 调用方无法再自行加锁.

3. 由于调用方无法自行加锁, 因此ConcurrentHashMap类提供了一些常见的复合操作. 如put-If-Absent,remove-if-equal, replace-if-equal等:

// 只有key不是集合中的键时才插入该键值对

V putIfAbsent(K key, V value); 

// 集合中存在该键值对时才删除

boolean remove(K key, V value); 

// 只有key和oldValue是集合中的键值对是才进行替换

boolean replace(K key, V oldValue, V newValue); 

// 只有key是集合中的key时才进行替换

V replace(K key, V newValue);

4. 迭代时不需要调用方进行额外的同步. ConcurrentHashMap使用的迭代器被称为weakly consistent(弱一致)迭代器, 弱一致迭代器不会在迭代期间抛出ConcurrentModificationException异常. 迭代开始后, 如果其他线程删除了ConcurrentHashMap集合的某个元素, 且被删除的元素尚未由next方法返回, 则该元素就不会被迭代器返回给调用方. 如果迭代开始后其他线程往ConcurrentHashMap集合中插入了新的元素, 那么新的元素可能会也可能不会被返回给调用方. 无论如何, 弱一致迭代器都保证不会将同一个元素多次返回给调用方. 

5. 调用ConcurrentHashMap对象的size, isEmpty等方法时(这些方法是针对整体Map的操作), 性能比较差. ConcurrentHashMap适合在要求高并发高性能的场合下使用, 在这些场景下, size或者isEmpty等方法用处不大, 这是可以接受的权衡.

ConcurrentHashMap的实现机制可参考http://www.ibm.com/developerworks/cn/java/java-lo-concurrenthashmap/index.html?ca=drs-

除了确实需要额外加锁的场景, ConcurrentHashMap都是比SynchronizedMap更好的选择.

 

CopyOnWriteArrayList类

同ArrayList一样, CopyOnWriteArrayList底层使用数组存储数据. CopyOnWriteArrayList中的数组定义为volatile, 以保证线程间的可见性. CopyOnWriteArrayList处理写操作(add, remove, set)时, 都会先copy一份数组, 然后在新的数组上进行写操作. 例如add方法:

public boolean add(E e) {
	final ReentrantLock lock = this.lock;
	lock.lock();
	try {
		// getArray返回的原先的底层数组
		Object[] elements = getArray();
		int len = elements.length;
		// copy数组中的数据
		Object[] newElements = Arrays.copyOf(elements, len + 1);
		// 加入新数据
		newElements[len] = e;
		// 改变底层数组
		setArray(newElements);
		return true;
	} finally {
		lock.unlock();
	}
}

这样的写操作肯定会导致性能大幅下降, 尤其是底层数组中包含很多数据的时候. 但是会带来一个优点: 处理读操作(get, iterator, contains等)时不需要进行同步和加锁. 由于读操作是针对当前的数组进行的, 如果读操作过程中其他线程并发修改了CopyOnWriteArrayList对象, 不会影响到当前数组. 所以读操作肯定是线程安全的:

public E get(int index) {
	return (E)(getArray()[index]);
}
public boolean contains(Object o) {
	Object[] elements = getArray();
	return indexOf(o, elements, 0, elements.length) >= 0;
}

迭代也是读操作操作的一种:

private static class COWIterator<E> implements ListIterator<E> {
	// 底层数组的快照
	private final Object[] snapshot;
	// 游标
	private int cursor;

	private COWIterator(Object[] elements, int initialCursor) {
		cursor = initialCursor;
		snapshot = elements;
	}

	public boolean hasNext() {
		return cursor < snapshot.length;
	}

	public boolean hasPrevious() {
		return cursor > 0;
	}

	public E next() {
		if (!hasNext())
			throw new NoSuchElementException();
		return (E) snapshot[cursor++];
	}

	public E previous() {
		if (!hasPrevious())
			throw new NoSuchElementException();
		return (E) snapshot[--cursor];
	}

	public int nextIndex() {
		return cursor;
	}

	public int previousIndex() {
		return cursor - 1;
	}

	/**
	 * 迭代器不支持remove操作
	 */
	public void remove() {
		throw new UnsupportedOperationException();
	}

	/**
	 * 迭代器不支持set操作
	 */
	public void set(E e) {
		throw new UnsupportedOperationException();
	}

	/**
	 * 迭代器不支持add操作
	 */
	public void add(E e) {
		throw new UnsupportedOperationException();
	}
}

创建迭代器时, 迭代器就初始化了当前数组的快照. 就算迭代期间进行了写操作, 也不会影响到迭代器中的snapshot数组. 所以CopyOnWriteArrayList返回的迭代器只反应迭代发生时CopyOnWriteArrayList对象所持有的集合, 迭代期间发生的改变不会反应出来.

总结:

1. CopyOnWriteArrayList是线程安全的, 且处理读操作不需要进行同步和加锁. 所以读操作具有很好的并发性.

2. CopyOnWriteArrayList的写操作是代价很大的, 所以CopyOnWriteArrayList只适用于读操作频率远远大于写操作频率的场景.

3. CopyOnWriteArrayList无法在调用方进行额外加锁. 同时CopyOnWriteArrayList也提供了一些常用的复合操作, 如putIfAbsent等.

4. CopyOnWriteArrayList的迭代只能反应迭代开始时CopyOnWriteArrayList对象所持有的集合. 迭代期间不会抛出ConcurrentModificationException异常, 调用方不需要进行额外的加锁(实际上也没有进行).

CopyOnWriteArraySet和CopyOnWriteArrayList具有类似的特点.

 

1
1
分享到:
评论

相关推荐

    Java并发编程实践(java concurrency in practice)pdf (java多线程总结.ppt)

    6. **并发集合**:Java提供了线程安全的集合,如`ConcurrentHashMap`、`CopyOnWriteArrayList`等,这些集合在并发环境中性能优异。书中会分析它们的设计原理和使用场景。 7. **线程池**:`ExecutorService`是线程池...

    Java Concurrency in Practice.zip

    《Java Concurrency in Practice》是Java并发编程领域的一本经典著作,由Brian Goetz、Tim Peierls、Joshua Bloch、Joseph Bowles和Doug Lea等专家共同编写。这本书深入探讨了Java平台上的多线程和并发编程,旨在...

    java_concurrency_in_practice_source源代码

    这里的"java_concurrency_in_practice_source"源代码正是书中实例的实现,它涵盖了Java多线程编程中的关键概念和技术。 1. **线程基础**:Java中创建线程有两种方式,一是通过`Thread`类的子类,二是实现`Runnable`...

    Concurrent_Programming+Java Concurrency in Practice+langspec

    首先,"Java Concurrency in Practice"是Java并发编程的经典之作,由Brian Goetz、Tim Peierls、Joshua Bloch、David Holmes和Doug Lea合著。这本书提供了一套实用的指导原则、设计模式和最佳实践,帮助Java开发者...

    Java Concurrency In Practice Learning Note

    本笔记将深入探讨《Java Concurrency In Practice》这本书中的核心概念,结合Guava库的实际使用案例,帮助读者理解并掌握Java并发编程的精髓。 首先,我们来了解Java并发的基础知识。Java提供了丰富的并发工具类,...

    Java Concurrency In Practice.pdf

    《Java Concurrency In Practice》是一本关于Java并发编程的经典著作,由Brian Göetz、Tim Peierls、Joshua Bloch、Joseph Bowbeer、David Holmes和Doug Lea共同编写。本书深入探讨了Java平台上的多线程编程技巧,...

    Java并发编程实践(Java Concurrency in Practice) (中英版)

    3. **并发集合与并发容器**:涵盖了Java并发集合框架,包括线程安全的ArrayList、LinkedList、HashMap等,并介绍了ConcurrentHashMap、CopyOnWriteArrayList等高效率的并发容器。 4. **并发工具**:讨论了Executor...

    Java Concurrency in Practice中文版

    《Java Concurrency in Practice》是Java并发编程领域的一本经典著作,由Brian Goetz、Tim Peierls、Joshua Bloch、Joe Bowbeer、David Holmes和Doug Lea合著,国内有热心人士进行了中文翻译,使得更多的中国开发者...

    Java Concurrency in Practice

    《Java Concurrency in Practice》是Java并发编程领域的一本经典著作,由Brian Goetz、Tim Peierls、Joshua Bloch、David Holmes和Doug Lea等多位Java并发领域的专家共同编写。这本书深入浅出地讲解了Java编程中的多...

    Java Concurrency in Practice CHM版本

    《Java Concurrency in Practice》是由Java并发库的主要开发者Doug Lea撰写的一本经典书籍,它深入探讨了Java编程中的多线程和并发编程技术。这本书是Java开发者掌握并发编程必备的参考文献,对于理解如何在Java环境...

    《Java Concurrency in Practice》源码

    《Java Concurrency in Practice》是Java并发编程领域的一本经典著作,由Brian Goetz、Tim Peierls、Joshua Bloch、David Holmes和Doug Lea合著。这本书深入探讨了如何在Java环境中有效地设计和实现多线程程序,强调...

    [Java并发编程实践].(Java.Concurrency.in.Practice).Brian.Goetz.英文原版.pdf

    - **并发集合**:Java提供了多种并发集合类,如`ConcurrentHashMap`等,用于解决多线程环境下数据结构的安全访问问题。 - **CompletableFuture**:这是一个强大的异步编程工具,可以简化异步操作的编写过程。书中...

    Java Concurrency in Practice Java并发编程

    《Java Concurrency in Practice》是Java并发编程领域的一本权威著作,由Brian Goetz、Tim Peierls、Joshua Bloch、David Holmes和Doug Lea等多位Java并发领域的专家共同编写。这本书深入探讨了Java平台上的多线程和...

    《Java Concurrency in Practice》代码示例

    《Java Concurrency in Practice》是Java并发编程领域的一本经典著作,由Brian Goetz、Tim Peierls、Joshua Bloch、David Holmes和Doug Lea合著。这本书深入浅出地探讨了Java平台上的多线程和并发编程,提供了丰富的...

Global site tag (gtag.js) - Google Analytics