`

并发集合ConcurrentSkipListMap的性能测试

阅读更多

 

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的性能比较(TreeMap、HashMap、ConcurrentSkipListMap)

    本测试查找方法使用Map的get方法,循环、离散获取。对于ConcurrentSkipListMap,获得顺序片段,可用subMap()方法,提取50w的子序列只需要1ms,具有巨大优势。 SkipListMap的范围查询效率比HashMap和TreeMap效率都要...

    Java concurrency集合之ConcurrentSkipListMap_动力节点Java学院整理

    Java concurrency集合之ConcurrentSkipListMap_动力节点Java学院整理,动力节点口口相传的Java黄埔军校

    构建高性能服务(一)ConcurrentSkipListMap和链表构建高性能Java Memcached

    NULL 博文链接:https://maoyidao.iteye.com/blog/1559420

    汪文君高并发编程实战视频资源下载.txt

     高并发编程第三阶段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中的方法使用,一半是...

    并发编程笔记20190526.docx

    第一章 线程基础、线程之间的共享和协作 3 一、基础概念 3 1. 什么是进程和线程 3 2. CPU核心数和线程数的关系 3 ...第五章 JMH性能测试 62 1、 JMH环境搭建 62 2、 执行 63 3、 基本概念 63 4、 注解与选项 63

    Java并发编程(学习笔记).xmind

    活跃度(Liveness)、性能、测试 避免活跃性危险 死锁 锁顺序死锁 资源死锁 动态的锁顺序死锁 开放调用 在协作对象之间发生的死锁 死锁的避免与诊断 支持定时的显示锁 通过...

    Java 常见并发容器总结

    - **`CopyOnWriteArrayList`** : 线程安全的 `List`,在读多写少的场合性能非常好,远远好于 `Vector`。 - **`ConcurrentLinkedQueue`** : 高效的并发队列,使用链表实现。可以看做一个线程安全的 `LinkedList`,这...

    Java集合教程吐血整理干货.md

    ConcurrentSkipListMap java集合 线程不安全的集合 HashMap的特点 HashMap在Jdk8之前使用拉链法实现,jdk8之后使用拉链法+红黑树实现。 HashMap是线程不安全的,并允许null key 和 null value。 HashMap在我当前的jdk...

    ConcurrentSkipListMap源码1

    简介跳表是一个随机化的数据结构,实质就是一种可以进行二分查找的有序链表。跳表在原有的有序链表上面增加了多级索引,通过索引来实现快速查找。跳表不仅能提高搜索性能,

    JAVA高并发包介绍

    ConcurrentSkipListMap等类的概念、原理、数据结构、使用场景描述。

    countries-routing-example:国家路由示例

    基于SpringBoot的应用程序在启动应用程序时通过RestTemplate从外部链接恢复数据,并加载到ConcurrentSkipListMap中,以通过get和put rest api管理并发。 我已经集成了openAPI来描述其余的API。 基本身份验证是通过...

Global site tag (gtag.js) - Google Analytics