java多线程基本概述(二十六)——免锁容器 -尊龙游戏旗舰厅官网
容器是所有编程中的基础工具,这其中也包括并发编程。出于这个原因,像vector和hashtable这类早期容器具有许多synchronized方法,当他们用于非多线程的应用程序中时,便会导致不可接受的开销。在java1.2中,新的容器类库是不同步的,并且collections类提供了各种static的同步的装饰方法,从而来同步不同类型的容器。尽管这是一种改进,因为它使你可以选择在你的容器中是否要使用同步,但是这种开销仍旧是基于synchronized加锁机制的。java se5特别添加了新容器,通过使用更灵巧的技术消除加锁,从而提高线程的安全的性能。
这些免锁容器背后的通用策略是:对容器的修改可以与读取操作同时发生,只要读取者只能看到完成修改后的结果即可。修改是在容器数据结构的某一部分的一个单独的副本(有时是整个数据结构的副本)上执行的,并且这个副本在修改过程中是不可视的。只有当修改完成时,被修改的结构才会自动地与主数据结构进行交换,之后读取者就可以看到这个修改了。
在copyonwritearraylist中,写入将导致创建整个底层数组的副本,而源数组将保留在原地,使得复制的数组在被修改时,读取操作可以安全的执行。当修改完成时,一个原子性操作将把新的数组换入,使得新的读取操作可以看到这个新的修改。copyonwritearraylist的好处之一是当多个迭代器同时遍历和修改这个列表时,不会抛出concurrentmodificationexception,因此你不必编写特殊的代码去防范这种异常,就像你以前必须作的那样。
迭代器上进行的元素更改操作(remove、set 和 add)不受支持。这些方法将抛出 unsupportedoperationexception。
copyonwritearrayset将使用copyonwritearraylist来实现其免锁行为。
concurrenthashmap和concurrentlinkedqueue使用了类似的技术,允许并发的读取和写入,但是容器中只有部分内容而不是整个容器可以被复制和修改。然而,任何修改在完成之前,读取者仍旧不能看到它们。concurrenthashmap不会抛出concurrentmodificationexception异常。
copyonwritearraylist适合用在“读多,写少”的“并发”应用中,换句话说,它适合使用在读操作远远大于写操作的场景里,比如缓存。它不存在“扩容”的概念,每次写操作(add or remove)都要copy一个副本,在副本的基础上修改后改变array引用,所以称为“copyonwrite”,因此在写操作是加锁,并且对整个list的copy操作时相当耗时的,过多的写操作不推荐使用该存储结构。
一个concurrenthashmap由多个segment组成,每一个segment都包含了一个hashentry数组的hashtable, 每一个segment包含了对自己的hashtable的操作,比如get,put,replace等操作,这些操作发生的时候,对自己的hashtable进行锁定。由于每一个segment写操作只锁定自己的hashtable,所以可能存在多个线程同时写的情况,性能无疑好于只有一个hashtable锁定的情况。
源码分析 在concurrenthashmap的remove,put操作还是比较简单的,都是将remove或者put操作交给key所对应的segment去做的,所以当几个操作不在同一个segment的时候就可以并发的进行。
public v remove(object key) {int hash = hash(key.hashcode());return segmentfor(hash).remove(key, hash, null);}而segment中的remove操作除了加锁之外和hashmap中的remove操作基本无异
v remove(object key, int hash, object value) {lock();try {int c = count - 1;hashentrypackage tij;import java.util.arraylist; import java.util.list; import java.util.concurrent.executorservice; import java.util.concurrent.executors;/*** created by huaox on 2017/4/21.**/ public class copyonwritearraylistdemo {private static class readtask implements runnable {list
输出结果:
exception in thread "pool-1-thread-3" java.util.concurrentmodificationexception main_0 main_1at java.util.arraylist$itr.checkforcomodification(arraylist.java:901) main_2 main_3at java.util.arraylist$itr.next(arraylist.java:851) main_4 main_0 main_1 write_2 main_3 main_4 main_0 main_1 write_2 write_3 main_4 main_0 write_0 write_1at tij.copyonwritearraylistdemo$readtask.run(copyonwritearraylistdemo.java:22) write_2 write_3at java.util.concurrent.threadpoolexecutor.runworker(threadpoolexecutor.java:1142) write_4at java.util.concurrent.threadpoolexecutor$worker.run(threadpoolexecutor.java:617)at java.lang.thread.run(thread.java:745)process finished with exit code 0免锁容器的源码为赋值底层数组,然后赋新值,改引用
public boolean add(e e) {final reentrantlock lock = this.lock;lock.lock();try {object[] elements = getarray();int len = elements.length;object[] newelements = arrays.copyof(elements, len 1);newelements[len] = e;setarray(newelements);return true;} finally {lock.unlock();}}修改为copyonwritearraylist后
public void run() {final int num = 5;list输出结果:
main_0 main_1 main_2 main_3 main_4 main_0 main_1 write_2 main_3 main_4 write_0 main_1 write_2 write_3 main_4 write_0 main_1 write_2 write_3 write_4 write_0 write_1 write_2 write_3 write_4process finished with exit code 0
转载于:https://www.cnblogs.com/soar-hu/p/6742694.html
总结
以上是尊龙游戏旗舰厅官网为你收集整理的java多线程基本概述(二十六)——免锁容器的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇:
- 下一篇: php安装加载yaf扩展