zoukankan      html  css  js  c++  java
  • synchronized与lock,哪个效率更高

    Java在一开始就提供了synchronized关键字,用于多线程之间的同步。它使用简便,不会出现拿锁之后不归还的情况,可以避免一些编程错误。

    而jdk5时提供的concurrent包里,有一个Lock接口以及它的实现类:ReentrantLock。这个类提供了更灵活的控制以及更强大的功能。

    如果单从性能方面考虑,两个哪个更高效呢?

    首先是单线程的加锁情况,见以下代码:

    import java.util.concurrent.locks.Lock; 
    import java.util.concurrent.locks.ReentrantLock;

    public class SynLockTest {

        public static void main(String[] args) { 
            long value = 0; 
            int MAX = 10000000; 
            Lock lock = new ReentrantLock(); 
            long start = System.nanoTime(); 
            for (int i = 0; i < MAX; i++) { 
                synchronized (new Object()) { 
                    value = value + 1; 
                } 
            } 
            long end = System.nanoTime(); 
            System.out.println("synchronized cost: " + (end – start)/1000000 + "ms");

            start = System.nanoTime(); 
            for (int i = 0; i < MAX; i++) { 
                lock.lock(); 
                try { 
                    value = value + 1; 
                } finally { 
                    lock.unlock(); 
                } 
            } 
            end = System.nanoTime(); 
            System.out.println("lock cost: " + (end – start) + "ns"); 
        } 
    }

    结果如下:

    synchronized cost: 405ms 
    lock cost: 479ms

    可见Lock的运行时间比synchronized略大。可以推测java编译器为synchronized做了特别优化。

    再考虑多线程情况:

    public class SynLockTest {

        static class SynRunner implements Runnable { 
            private long v = 0;

            @Override 
            public synchronized void run() { 
                v = v + 1; 
            } 
        }

        static class LockRunner implements Runnable { 
            private ReentrantLock lock = new ReentrantLock(); 
            private long v = 0;

            @Override 
            public void run() { 
                lock.lock(); 
                try { 
                    v = v + 1; 
                } finally { 
                    lock.unlock(); 
                } 
            }

        }

        static class Tester { 
            private AtomicLong runCount = new AtomicLong(0); 
            private AtomicLong start = new AtomicLong(); 
            private AtomicLong end = new AtomicLong();

            public Tester(final Runnable runner, int threadCount) { 
                final ExecutorService pool = Executors.newFixedThreadPool(threadCount); 
                Runnable task = new Runnable() { 
                    @Override 
                    public void run() { 
                        while (true) { 
                            runner.run(); 
                            long count = runCount.incrementAndGet(); 
                            if (count == 1) { 
                                start.set(System.nanoTime()); 
                            } else if (count >= 10000000) { 
                                if (count == 10000000) { 
                                    end.set(System.nanoTime()); 
                                    System.out.println(runner.getClass().getSimpleName() + ", cost: " 
                                            + (end.longValue() – start.longValue())/1000000 + "ms");                            } 
                                    pool.shutdown(); 
                                return; 
                            } 
                        } 
                    } 
                }; 
                for (int i = 0; i < threadCount; i++) { 
                    pool.submit(task); 
                } 
            } 
        }

        public static void main(String[] args) { 
            new Tester(new SynRunner(), 1); 
            new Tester(new LockRunner(), 1); 
        }

    }

    现在测试不同线程下的表现(时间单位ms):

      1 10 50 100 500 1000 5000
    synchronized 542 4894 4667 4700 5151 5156 5178
    lock 838 1211 821 847 851 1211 1241

    可以看到,在多线程环境并存在大量竞争的情况下,synchronized的用时迅速上升,而lock却依然保存不变或增加很少。

    Lock是用CAS来实现的
    JDK 1.6以上synchronized也改用CAS来实现了,所以两者性能差不多
    Lock提供的功能丰富点,synchronized的使用简单点

  • 相关阅读:
    dubbo注册服务IP解析异常及IP解析源码分析
    Linux下安装并破解StarUML
    Mysql中int(1)的误解及说明
    grep参数说明及常用用法
    ubuntu中使用nginx把本地80端口转到其他端口
    IDEA下安装/配置Jrebel
    Eclipse下安装/配置Jrebel6.X
    shell脚本问题read: Illegal option -t
    docker pull 提示错误的username or password
    linux 安装 rpm 的jdk
  • 原文地址:https://www.cnblogs.com/azhqiang/p/3945402.html
Copyright © 2011-2022 走看看