• Java 中锁之间的对比


    synchronized 和  java.util.concurrent.lock.Lock 之间的区别

    • 实现层面不一样。synchronized 是 Java 关键字,JVM层面 实现加锁和释放锁;Lock 是一个接口,在代码层面实现加锁和释放锁
    • 是否自动释放锁。synchronized 在线程代码执行完或出现异常时自动释放锁;Lock 不会自动释放锁,需要在 finally {} 代码块显式地中释放锁
    • 是否一直等待。synchronized 会导致线程拿不到锁一直等待;Lock 可以设置尝试获取锁或者获取锁失败一定时间超时
    • 获取锁成功是否可知。synchronized 无法得知是否获取锁成功;Lock 可以通过 tryLock 获得加锁是否成功
    • 功能复杂性。synchronized 加锁可重入、不可中断、非公平;Lock 可重入、可判断、可公平和不公平、细分读写锁提高效率

    java.util.concurrent.lock.Lock 与  java.util.concurrent.lock.ReadWriteLock 之间的区别

    • ReadWriteLock 定义了获取读锁和写锁的接口,读锁之间不互斥,非常适合读多、写少的场景

    适用场景

    • JDK 1.6 开始,对 synchronized 方式枷锁进行了优化,加入了偏向锁、轻量级锁和锁升级机制,性能得到了很大的提升。性能与 ReentrantLock  差不多
    • 读多写少的情况下,考虑使用 ReadWriteLock 

    synchronized、ReentrantLock、ReentrantReadWriteLock 启动 990 个线程读共享变量,10 个线程写共享变量

    package constxiong.concurrency.a020;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.UUID;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReadWriteLock;
    import java.util.concurrent.locks.ReentrantLock;
    import java.util.concurrent.locks.ReentrantReadWriteLock;
    
    /**
     * JDK 1.8 中锁性能的测试
     * @author ConstXiong
     */
    public class TestLockPerformance {
        
        public static Object obj = new Object();//用于 synchronized 获取锁
        
        public static Lock lock = new ReentrantLock();//可重入锁
        
        public static ReadWriteLock readWriteLock = new ReentrantReadWriteLock();//读写锁
        
        public static final int READ = 0;
        
        public static final int WRITE = 1;
        
        // uuid,一个随机字符串
        public static String uuid = UUID.randomUUID().toString();
    
        public static void main(String[] args) throws InterruptedException {
    //        testSynchronized(1000);
            
            testReentrantLock(1000);
            
    //        testReadWriteLock(1000);
        }
        
        public static void testSynchronized(int threadNum) throws InterruptedException {
            long t1 = System.currentTimeMillis();
            List<Thread> tList = new ArrayList<Thread>();
            //启动 threadNum - 向上取整 (0.01 * threadNum) 个线程读 uuid, 向上取整 (0.01 * threadNum) 个线程写 uuid
            for (int i = 0; i < threadNum; i++) {
                Thread t;
                if (i % 100 == 0) {
                    t = new Thread(new WorkerSynchronized(WRITE));
                } else {
                    t = new Thread(new WorkerSynchronized(READ));
                }
                t.start();//启动线程
                tList.add(t);
            }
            
            for (Thread t : tList) {
                t.join();
            }
            
            long t2 = System.currentTimeMillis();
            System.out.println("testSynchronized 耗时:" + (t2 - t1));
        }
        
        public static void testReentrantLock(int threadNum) throws InterruptedException {
            long t1 = System.currentTimeMillis();
            List<Thread> tList = new ArrayList<Thread>();
            //启动 threadNum - 向上取整 (0.01 * threadNum) 个线程读 uuid, 向上取整 (0.01 * threadNum) 个线程写 uuid
            for (int i = 0; i < threadNum; i++) {
                Thread t;
                if (i % 100 == 0) {
                    t = new Thread(new WorkerReentrantLock(WRITE));
                } else {
                    t = new Thread(new WorkerReentrantLock(READ));
                }
                t.start();//启动线程
                tList.add(t);
            }
            
            for (Thread t : tList) {
                t.join();
            }
            
            long t2 = System.currentTimeMillis();
            System.out.println("testReentrantLock 耗时:" + (t2 - t1));
        }
        
        public static void testReadWriteLock(int threadNUm) throws InterruptedException {
            long t1 = System.currentTimeMillis();
            List<Thread> tList = new ArrayList<Thread>();
            //启动 threadNum - 向上取整 (0.01 * threadNum) 个线程读 uuid, 向上取整 (0.01 * threadNum) 个线程写 uuid
            for (int i = 0; i < threadNUm; i++) {
                Thread t;
                if (i % 100 == 0) {
                    t = new Thread(new WorkerReadWriteLock(WRITE));
                } else {
                    t = new Thread(new WorkerReadWriteLock(READ));
                }
                t.start();//启动线程
                tList.add(t);
            }
            
            for (Thread t : tList) {
                t.join();
            }
            
            long t2 = System.currentTimeMillis();
            System.out.println("testReadWriteLock 耗时:" + (t2 - t1));
        }
        
    }
    
    //工作线程,使用 synchronized 关键字加锁
    class WorkerSynchronized implements Runnable {
        //0-read;1-write
        private int type;
        
        WorkerSynchronized(int type) {
            this.type = type;
        }
        
        //加锁读 TestLockPerformance.uuid 变量,并打印
        private void read() {
            synchronized (TestLockPerformance.obj) {
                //休眠 20 毫秒,模拟任务执行耗时
                try {
                    Thread.sleep(20);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + 
                        " read uuid = " +  TestLockPerformance.uuid);
            }
        }
        
        //加锁写 TestLockPerformance.uuid 变量,并打印
        private void write() {
            synchronized (TestLockPerformance.obj) {
                //休眠 20 毫秒,模拟任务执行耗时
                try {
                    Thread.sleep(20);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                TestLockPerformance.uuid = UUID.randomUUID().toString();
                System.out.println(Thread.currentThread().getName() + 
                        " write uuid = " +  TestLockPerformance.uuid);
            }
        }
        
        @Override
        public void run() {
            //type = 0,线程读 TestLockPerformance.uuid 变量
            if (type == 0) {
                read();
            //type = 1,线程生成 uuid,写入 TestLockPerformance.uuid 变量
            } else {
                write();
            }
        }
    }
    
    //工作线程,使用 ReentrantLock 加锁
    class WorkerReentrantLock implements Runnable {
        //0-read;1-write
        private int type;
        
        WorkerReentrantLock(int type) {
            this.type = type;
        }
        
        //加锁读 TestLockPerformance.uuid 变量,并打印
        private void read() {
            TestLockPerformance.lock.lock();
            try {
                //休眠 20 毫秒,模拟任务执行耗时
                try {
                    Thread.sleep(20);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + 
                        " read uuid = " +  TestLockPerformance.uuid);
            } finally {
                TestLockPerformance.lock.unlock();
            }
            
        }
        
        //加锁写 TestLockPerformance.uuid 变量,并打印
        private void write() {
            TestLockPerformance.lock.lock();
            try {
                //休眠 20 毫秒,模拟任务执行耗时
                try {
                    Thread.sleep(20);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                TestLockPerformance.uuid = UUID.randomUUID().toString();
                System.out.println(Thread.currentThread().getName() + 
                        " write uuid = " +  TestLockPerformance.uuid);
            } finally {
                TestLockPerformance.lock.unlock();
            }
        }
        
        @Override
        public void run() {
            //type = 0,线程读 TestLockPerformance.uuid 变量
            if (type == 0) {
                read();
            //type = 1,线程生成 uuid,写入 TestLockPerformance.uuid 变量
            } else {
                write();
            }
        }
    }
    
    
    //工作线程,使用 ReentrantReadWriteLock 关键字加锁
    class WorkerReadWriteLock implements Runnable {
        //0-read;1-write
        private int type;
        
        WorkerReadWriteLock(int type) {
            this.type = type;
        }
        
        //加锁读 TestLockPerformance.uuid 变量,并打印
        private void read() {
            TestLockPerformance.readWriteLock.readLock().lock();
            try {
                //休眠 20 毫秒,模拟任务执行耗时
                try {
                    Thread.sleep(20);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + 
                        " read uuid = " +  TestLockPerformance.uuid);
            } finally {
                TestLockPerformance.readWriteLock.readLock().unlock();
            }
        }
        
        //加锁写 TestLockPerformance.uuid 变量,并打印
        private void write() {
            TestLockPerformance.readWriteLock.writeLock().lock();
            try {
                //休眠 20 毫秒,模拟任务执行耗时
                try {
                    Thread.sleep(20);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                TestLockPerformance.uuid = UUID.randomUUID().toString();
                System.out.println(Thread.currentThread().getName() + 
                        " write uuid = " +  TestLockPerformance.uuid);
            } finally {
                TestLockPerformance.readWriteLock.writeLock().unlock();
            }
        }
        
        @Override
        public void run() {
            //type = 0,线程读 TestLockPerformance.uuid 变量
            if (type == 0) {
                read();
            //type = 1,线程生成 uuid,写入 TestLockPerformance.uuid 变量
            } else {
                write();
            }
        }
    }

    调用测试方法 

    testSynchronized(1000);

    耗时

    Thread-0 write uuid = b7fb63d7-79cc-4cc0-84ed-5a9cd4de6824
    Thread-252 read uuid = b7fb63d7-79cc-4cc0-84ed-5a9cd4de6824
    Thread-251 read uuid = b7fb63d7-79cc-4cc0-84ed-5a9cd4de6824
    .
    .
    .
    Thread-255 read uuid = d666bfe6-dc71-4df2-882a-d530a59d7e92
    Thread-254 read uuid = d666bfe6-dc71-4df2-882a-d530a59d7e92
    Thread-253 read uuid = d666bfe6-dc71-4df2-882a-d530a59d7e92
    testSynchronized 耗时:22991

    调用测试方法 

    testReentrantLock(1000);

    耗时

    Thread-0 write uuid = 4352eb13-d284-47ec-8caa-fc81d91d08e1
    Thread-1 read uuid = 4352eb13-d284-47ec-8caa-fc81d91d08e1
    Thread-485 read uuid = 4352eb13-d284-47ec-8caa-fc81d91d08e1
    .
    .
    .
    Thread-997 read uuid = 9d7f0a78-5eb7-4506-9e98-e8e9a7a717a5
    Thread-998 read uuid = 9d7f0a78-5eb7-4506-9e98-e8e9a7a717a5
    Thread-999 read uuid = 9d7f0a78-5eb7-4506-9e98-e8e9a7a717a5
    testReentrantLock 耗时:22935

    调用测试方法 

    testReadWriteLock(1000);

    耗时

    Thread-0 write uuid = 81c13f80-fb19-4b27-9d21-2e99f8c8acbd
    Thread-277 read uuid = 81c13f80-fb19-4b27-9d21-2e99f8c8acbd
    Thread-278 read uuid = 81c13f80-fb19-4b27-9d21-2e99f8c8acbd
    .
    .
    .
    Thread-975 read uuid = 35be0359-1973-4a4f-85b7-918053d841f7
    Thread-971 read uuid = 35be0359-1973-4a4f-85b7-918053d841f7
    Thread-964 read uuid = 35be0359-1973-4a4f-85b7-918053d841f7
    testReadWriteLock 耗时:543

    通过耗时测试可以看出,使用 synchronized 和 ReentrantLock 耗时相近;但是由于 990 个线程读,10 个线程写,使用 ReentrantReadWriteLock 耗时 543 毫秒。

    PS:JDK 并发包里的工具类,还有很多适合特定场景的工具,后面我们继续探索。

     来一道刷了进BAT的面试题?

  • 相关阅读:
    快速排序就这么简单
    Shiro入门这篇就够了【Shiro的基础知识、回顾URL拦截】
    SpringDataJPA入门就这么简单
    递归就这么简单
    SpringBoot就是这么简单
    Activiti就是这么简单
    Lucene就是这么简单
    过来人告诉你,去工作前最好还是学学Git
    给女朋友讲解什么是Git
    我终于看懂了HBase,太不容易了...
  • 原文地址:https://www.cnblogs.com/ConstXiong/p/11687834.html
Copyright © 2020-2023  润新知