ConcurrentSkipListMap是Doug Lea在java6中新加入的一个并发集合,下面这个例子主要是测试ConcurrentSkipListMap的插入、读取和并发修改集合元素时的性能特征,代码如下:
package test.caipiao.log; import java.io.File; import java.io.IOException; import java.nio.charset.Charset; import java.util.concurrent.ConcurrentNavigableMap; import java.util.concurrent.ConcurrentSkipListMap; import java.util.concurrent.atomic.AtomicInteger; import java.util.ArrayList; import java.util.Iterator; import java.util.Map; import java.util.Set; import com.caipiao.util.io.FileUtils; public class ConcurrentSkipListMapTest2 { public static void main(String[] args) throws InterruptedException, Exception { final ConcurrentNavigableMap<Integer, String> cslm = new ConcurrentSkipListMap<Integer, String>(); final Counter5 counter = new Counter5(); // create 100 threads ArrayList<MyThread5> threads = new ArrayList<MyThread5>(); for (int x = 0; x < 100; x++) { threads.add(new MyThread5(counter, cslm)); } long start1 = System.currentTimeMillis(); // start all of the threads Iterator i1 = threads.iterator(); while (i1.hasNext()) { MyThread5 mt = (MyThread5) i1.next(); mt.start(); } // wait for all the threads to finish Iterator i2 = threads.iterator(); while (i2.hasNext()) { MyThread5 mt = (MyThread5) i2.next(); mt.join(); } long end1 = System.currentTimeMillis(); System.out.println("100个线程 每个线程插入100000共1000万条记录,耗时: " + (end1 - start1) + " 毫秒"); System.out.println("Count: " + counter.getCount()); System.out.println("original size = " + cslm.size()); System.out.println("---------------------以上是测试插入---------------------------------------"); // create 1000 threads ArrayList<MyThread7> threads3 = new ArrayList<MyThread7>(); for (int x = 0; x < 1000; x++) { threads3.add(new MyThread7(counter, cslm)); } long start3 = System.currentTimeMillis(); // start all of the threads Iterator i3 = threads3.iterator(); while (i3.hasNext()) { MyThread7 mt = (MyThread7) i3.next(); mt.start(); } // wait for all the threads to finish Iterator i33 = threads3.iterator(); while (i33.hasNext()) { MyThread7 mt = (MyThread7) i33.next(); mt.join(); } long end3 = System.currentTimeMillis(); System.out.println("1000个线程 每个线程插入10000共1000万条记录,耗时: " + (end3 - start3) + " 毫秒"); System.out.println("---------------------以上是测试读取---------------------------------------"); long start2 = System.currentTimeMillis(); ArrayList<MyThread6> threads2 = new ArrayList<MyThread6>(); for (int x = 0; x < 5; x++) { threads2.add(new MyThread6(counter, cslm)); } // start all of the threads Iterator i12 = threads2.iterator(); //并发修改 访问 ConcurrentSkipListMap while (i12.hasNext()) { MyThread6 mt = (MyThread6) i12.next(); mt.start(); } Thread t = new Thread() { public void run() { for (int x = 0; x < 100000; x++) { String s = cslm.get(x); if (x % 20 == 0) { // System.out.println("key ---" + x + " s--- " + s); } } } }; t.start(); // wait for all the threads to finish Iterator i22 = threads2.iterator(); while (i22.hasNext()) { MyThread6 mt = (MyThread6) i22.next(); mt.join(); } t.join(); long end2 = System.currentTimeMillis(); System.out.println(end2 - start2); System.out.println("over"); System.out.println("new size = " + cslm.size()); System.out.println("---------------------以上是测试并发的修改ConcurrentSkipListMap里的元素---------------------------------------"); } } // thread that increments the counter 100000 times. class MyThread5 extends Thread { Counter5 counter; ConcurrentNavigableMap<Integer, String> cslm; MyThread5(Counter5 counter, ConcurrentNavigableMap<Integer, String> cslm) { this.counter = counter; this.cslm = cslm; } public void run() { for (int x = 0; x < 100000; x++) { int i = counter.incrementCount(); cslm.put(i, ""); } } } // class that uses AtomicInteger for counter class Counter5 { private AtomicInteger count = new AtomicInteger(0); public int incrementCount() { return count.incrementAndGet(); } public int decrementAndGet() { return count.decrementAndGet(); } public int getCount() { return count.get(); } } //class that uses to delete part data of the cslm class MyThread6 extends Thread { Counter5 counter; ConcurrentNavigableMap<Integer, String> cslm; MyThread6(Counter5 counter, ConcurrentNavigableMap<Integer, String> cslm) { this.counter = counter; this.cslm = cslm; } public void run() { for (int x = 0; x < 100000; x++) { cslm.remove(x); try { if (x % 100 == 0) { this.sleep(1); } } catch (InterruptedException e) { e.printStackTrace(); } } } } //thread that decrements the counter 100000 times. class MyThread7 extends Thread { Counter5 counter; ConcurrentNavigableMap<Integer, String> cslm; MyThread7(Counter5 counter, ConcurrentNavigableMap<Integer, String> cslm) { this.counter = counter; this.cslm = cslm; } public void run() { for (int x = 0; x < 10000; x++) { int i = counter.decrementAndGet(); cslm.get(i); } } }
CPU配置为4核 intel i3-2100 3.1GHz,内存分配1G,多次运行输出大致如下:
100个线程 每个线程插入100000共1000万条记录,耗时: 4719 毫秒
Count: 10000000
original size = 10000000
---------------------以上是测试插入---------------------------------------
1000个线程 每个线程插入10000共1000万条记录,耗时: 2684 毫秒
---------------------以上是测试读取---------------------------------------
1025
over
new size = 9900001
-------------------以上是测试并发的修改、访问ConcurrentSkipListMap里的元素------------------------------------
可以看到put操作的并发能达到200万/秒以上,get操作的并发能达到350万/秒以上,
这里的性能损耗有一部分是在AtomicInteger原子的递增和递减上,如果在真实的业务场景中,可以知道key的操作不需要使用AtomicInteger或加锁方式来获取,性能会更高。
通过第三个输出可以知道对ConcurrentSkipListMap访问的同时进行删除不会出现ConcurrentModificationException异常。
此例子可以把ConcurrentSkipListMap换成ConcurrentHashMap等其它集合进行测试。
如果把threads的线程数创建为10000个而每个线程执行1000次,是可以正常输出的。
把ConcurrentSkipListMap换成ConcurrentHashMap,在把threads的线程数创建为10000个而每个线程执行1000次,在线程数执行不到5000的时候会报java.lang.OutOfMemoryError: unable to create new native thread,但把每个线程的执行次数改为100的时候,可以正常的执行下去。在ConcurrentHashMap的put操作中有tryLock()这个操作会涉及到线程操作,而在ConcurrentSkipListMap的put操作中没有涉及线程操作,具体原因只有仔细的看看源码才能解释。
相关推荐
在Java编程中,Map接口是用于存储键值对的数据结构,而Java提供了多种Map的实现,包括TreeMap、HashMap和ConcurrentSkipListMap。...在实际使用中,应结合性能测试和业务需求来确定最适合的Map类型。
Java concurrency集合之ConcurrentSkipListMap_动力节点Java学院整理,动力节点口口相传的Java黄埔军校
这些队列在多线程环境下的性能表现优秀,能够有效减少锁竞争,提高并发性能。 总结来说,`ConcurrentSkipListMap`提供了高效并发的有序映射解决方案,适用于需要线程安全和快速查找的场景。而在构建高性能Java ...
然而,这种全局锁机制会带来性能瓶颈,因为所有操作都需要获取整个容器的锁,导致并发性能下降。 为了解决同步容器的性能问题,Java 引入了并发容器。并发容器位于 `java.util.concurrent` 包下,其中包含多种专门...
7. **JVM与并发**:探讨了JVM对并发的支持,包括内存模型、垃圾收集与并发的关系,以及如何调整JVM参数以优化并发性能。 8. **实战演练**:书中包含大量实战案例,让读者能够在实践中理解和掌握并发编程技巧。 9. ...
对`ConcurrentSkipListMap`的源码分析,可以帮助我们理解其内部机制,如如何处理并发操作、如何构建和维护索引、以及在复杂并发场景下的性能表现等。 通过深入理解`ConcurrentSkipListMap`的实现,我们可以更好地...
高并发编程第三阶段12讲 sun.misc.Unsafe介绍以及几种Counter方案性能对比.mp4 高并发编程第三阶段13讲 一个JNI程序的编写,通过Java去调用C,C++程序.mp4 高并发编程第三阶段14讲 Unsafe中的方法使用,一半是...
高并发编程第三阶段12讲 sun.misc.Unsafe介绍以及几种Counter方案性能对比.mp4 高并发编程第三阶段13讲 一个JNI程序的编写,通过Java去调用C,C++程序.mp4 高并发编程第三阶段14讲 Unsafe中的方法使用,一半是...
- **数据库连接池管理**:如C3P0、HikariCP等,提高数据库并发性能。 - **微服务架构下的并发设计**:在微服务场景下,如何设计和优化并发策略。 以上知识点涵盖了Java高并发系统设计的核心内容,理解和掌握这些...
- JDK 1.7:使用分段锁机制,提高并发性能,但写操作可能导致整个段锁定。 - JDK 1.8:采用节点链表和红黑树结构,减少锁粒度,提供更好的性能和空间效率。 - 变化:从分段锁到单一锁,增加节点类型,优化查找、...
它们内部采用了高级并发策略,如分段锁和读写分离,提高了并发性能。 6. **原子变量**:`java.util.concurrent.atomic`包中的原子变量类,如`AtomicInteger`、`AtomicLong`等,提供了无锁编程的支持,可以在不使用...
`ConcurrentHashMap`通过分段锁和细粒度锁的机制提高了并发性能,而`ConcurrentSkipListMap`则利用跳表的数据结构特性提供了优秀的线程安全性能。开发者可以根据实际应用场景选择合适的集合类,以满足不同的并发需求...
9. **并发集合**:Java提供了一些并发友好的集合类,如ConcurrentHashMap、CopyOnWriteArrayList和ConcurrentSkipListMap,它们在多线程环境下具有更好的性能和安全性。 10. **集合的不可变性**:Collections....
面试中,Java集合框架的题目通常会测试应聘者对数据结构、算法以及API的理解。以下是对Java集合框架的一些核心知识点的详细阐述: 1. **集合与接口**:Java集合框架包括List、Set和Queue等接口,它们都是继承自...
5. Concurrentxxx类:ConcurrentHashMap是最常用的并发集合,它通过分段锁技术实现线程安全,允许多个线程并发访问不同的段,提高了并发性能。此外,还有ConcurrentSkipListSet和ConcurrentSkipListMap等。 6. ...
活跃度(Liveness)、性能、测试 避免活跃性危险 死锁 锁顺序死锁 资源死锁 动态的锁顺序死锁 开放调用 在协作对象之间发生的死锁 死锁的避免与诊断 支持定时的显示锁 通过...
它通过将数据分成多个段(segment),每个段有自己的锁,这样可以同时对不同的段进行操作而不会发生冲突,从而提高并发性能。在Java 8及以后版本中,`ConcurrentHashMap`进一步优化了设计,采用了一种更加灵活的分段锁...
并发容器在Java多线程环境下发挥着至关重要的作用,它们的设计旨在解决非线程安全容器在高并发场景下的性能瓶颈问题。接下来,我们将逐一探讨几种主要的并发容器。 ### 1. CopyOnWriteArrayList #### 1.1 原理概述...
5. **并发容器**:如ArrayList、LinkedList、Vector、ConcurrentHashMap等,讨论它们在并发环境下的特性和使用注意事项,尤其是并发容器(如ConcurrentLinkedQueue、ConcurrentSkipListMap)的设计和使用。...