简单测试Java线程安全中阻塞同步与非阻塞同步性能

摘抄自周志明老师的《深入理解Java虚拟机:JVM高级特性与最佳实践》13.2.2 线程安全的实现方法

1.名词解释

同步是指锁哥线程并发访问共享数据时,保证共享数据同一时刻只被一个线程访问

互斥同步(阻塞同步)是一种悲观的并发策略,总是认为只要不去做正确的同步措施(加锁),那就肯定会出现问题。

阻塞同步最主要的问题是进行线程阻塞和唤醒所带来的性能问题,因为在JDK 1.2之后,Java的线程模型被替换为基于操作系统原生线程模型来实现,如要阻塞唤醒一个线程,都需要操作系统来帮忙完成,这就需要用户态转换到内核态,会耗费很多时间。

非阻塞同步:随着硬件指令集的发展,我们有了另一种选择:基于冲突检测的乐观并发策略,这种操作不需要挂起线程,会节省很多时间,比如CAS(compare and swap)指令。

2.开始测试

第一种加锁方式:

    static int a=0;
    public static void lock() {
        Thread[] threads=new Thread[50];
        for(int i=0;i<threads.length;i++){
            threads[i]=new Thread(new Runnable() {
                
                @Override
                public void run() {
                    for(int i=0;i<100000;i++){
                        synchronized(Main.class){
                            a++;
                        }
                    }
                }
            });
            threads[i].start();
        }
        while(Thread.activeCount() > 1){
            Thread.yield();
        }
        System.out.println(a);
    }

第二种CAS方式:

    static AtomicInteger integer=new AtomicInteger(0);
    public static void cas() {
        Thread[] threads=new Thread[50];
        for(int i=0;i<threads.length;i++){
            threads[i]=new Thread(new Runnable() {
                
                @Override
                public void run() {
                    for(int i=0;i<100000;i++){
                        integer.incrementAndGet();
                    }
                }
            });
            threads[i].start();
        }
        while(Thread.activeCount() > 1){
            Thread.yield();
        }
        System.out.println(integer.get());
    }

3结论:运行两个方法,同样是50个线程,100000个自增,输出时间差,可以看到性能之间的差异。

lock方法平均在1270ms

cas方法平均在175ms

可以看到阻塞同步与非阻塞同步之间巨大的差异,也可以看出Java线程用户态内核态切换损耗的处理器时间很大。

 

posted @ 2018-10-22 16:55  欲戴王冠.必承其重  阅读(545)  评论(0编辑  收藏  举报