zoukankan      html  css  js  c++  java
  • 浅谈Lock

    javaLock是一个接口:
    在这里插入图片描述
    根据方法名字,基本知道方法的主要用途。命名很重要。。。

    ReentrantLock

    ,可重入锁,ReentrantLock是唯一实现了Lock接口的类,简单的测试:
    在这里插入图片描述
    Lock应该放在成员变量里面,如果放在方法里面,每次执行都会new一个新的Lock,就不是同一个lock了
    在这里插入图片描述
    lock放在方法里面,执行出来多个线程在获得锁:
    在这里插入图片描述
    tryLock() & tryLock(long time, TimeUnit unit)顾名思义,就是尝试获取锁,可以加时间,tryLock(long time, TimeUnit unit) 能够响应中断,即支持对获取锁的中断,但是但尝试获取一个内部锁(synchronized)的操作是不能被中断,返回的是boolean类型这里可以进行判断,如果获取到了锁,则进行啥,若没有获取到锁执行啥,
    在这里插入图片描述
    测试代码:

    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class LockTest {
    
        private Lock lock = new ReentrantLock();
        /**
         *     true 表示 ReentrantLock 的公平锁
         */
        private ReentrantLock lock = new ReentrantLock(true);
    
        public static void main(String[] args) {
            //简单的使用
            test1();
            //trylock
            test2();
            //中断锁
            test3();
        }
    
        public static void test1() {
            LockTest lockTest = new LockTest();
            for (int i = 0; i < 10; i++) {
                //线程1
                new Thread(() -> {
                    lockTest.method1(Thread.currentThread());
                }, i + "").start();
            }
        }
    
        //需要参与同步的方法
        private void method1(Thread thread) {
            //错误
    //        Lock lock = new ReentrantLock();
            lock.lock();
            try {
                System.out.println("线程名" + thread.getName() + "获得了锁");
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                System.out.println("线程名" + thread.getName() + "释放了锁");
                lock.unlock();
            }
        }
    
        public static void test2() {
            LockTest lockTest = new LockTest();
            for (int i = 0; i < 10; i++) {
                //线程1
                new Thread(() -> {
                    lockTest.method2(Thread.currentThread());
                }, i + "").start();
            }
        }
    
        //需要参与同步的方法
        private void method2(Thread thread) {
    
    //        尝试获取锁
            boolean b = lock.tryLock();
    
            //        尝试获取锁时间
    //        boolean b = false;
    //        try {
    //            System.out.println("线程名" + thread.getName() + "尝试获取锁--");
    //            b = lock.tryLock(2, TimeUnit.SECONDS);
    //        } catch (InterruptedException e) {
    //            e.printStackTrace();
    //        }
    
            if (!b) {
                //未获取到锁
                System.out.println("线程名" + thread.getName() + "没有获取到锁,直接返回--");
                return;
            }
            //获取到锁
            try {
                TimeUnit.SECONDS.sleep(2);
                System.out.println("线程名" + thread.getName() + "获得了锁");
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                System.out.println("线程名" + thread.getName() + "释放了锁");
                lock.unlock();
            }
        }
    
        public static void test3() {
            LockTest lockTest = new LockTest();
            //线程1
            Thread t1 = new Thread(() -> {
                try {
                    lockTest.method3(Thread.currentThread());
                } catch (InterruptedException e) {
                    System.out.println("线程名t1中断-----");
    //                e.printStackTrace();
                }
            }, "t1");
            t1.start();
    //线程1
            Thread t2 = new Thread(() -> {
                try {
                    lockTest.method3(Thread.currentThread());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }, "t2");
            t2.start();
    
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            System.out.println("线程名t1执行中断");
            t1.interrupt();
        }
    
        //需要参与同步的方法
        private void method3(Thread thread) throws InterruptedException {
            lock.lockInterruptibly();
            //获取到锁
            System.out.println("线程名" + thread.getName() + "获得了锁");
            try {
                TimeUnit.SECONDS.sleep(10);
            } catch (Exception e) {
    //            e.printStackTrace();
            } finally {
                System.out.println("线程名" + thread.getName() + "释放了锁");
                lock.unlock();
            }
        }
    
    }
    

    默认的ReentrantLock是不公平的锁,
    在这里插入图片描述
    公平锁,公平指的是,谁先尝试获取锁,谁就能获取到锁,不公平的话,就是有可能一个线程最先尝试获取锁,但是一直没有获取到锁,获取锁都是随机的.可以通过构造方法创建公平锁:
    在这里插入图片描述
    在这里插入图片描述

    非公平锁性能高于公平锁性能。首先,在恢复一个被挂起的线程与该线程真正运行之间存在着严重的延迟。而且,非公平锁能更充分的利用cpu的时间片,尽量的减少cpu空闲的状态时间。

    ReadWriteLock

    读写锁,跟lock接口没啥关系主要实现有ReentrantReadWriteLock
    在这里插入图片描述
    在这里插入图片描述
    demo:

    public class ReadWriteLockTest {
    
        private static ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
    
        private static Integer count = 0;
    
        public static void main(String[] args) {
            ReadWriteLockTest readWriteLockTest = new ReadWriteLockTest();
            for (int i = 0; i < 100; i++) {
                //从1到10的int型随数
                int j = (int) (1 + Math.random() * (10 - 1 + 1));
                if (j % 4 != 1) {
                    //写操作
                    new Thread("" + i) {
                        public void run() {
                            readWriteLockTest.get(Thread.currentThread());
                        }
                    }.start();
                } else {
                    //读操作
                    int co = i;
                    new Thread("" + i) {
                        public void run() {
                            readWriteLockTest.write(Thread.currentThread(), co);
                        }
                    }.start();
                }
            }
    
        }
    
        public static void get(Thread thread) {
            rwl.readLock().lock();
            try {
                System.out.println("线程" + thread.getName() + "开始读操作...");
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("线程" + thread.getName() + "读操作完毕..." + count);
            } finally {
                rwl.readLock().unlock();
            }
        }
    
        public static void write(Thread thread, int i) {
            rwl.writeLock().lock();
            try {
                System.out.println("线程" + thread.getName() + "开始写操作---------"+i);
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                count = i;
                System.out.println("线程" + thread.getName() + "开始写操作完成------"+i);
            } finally {
                rwl.writeLock().unlock();
            }
        }
    
    
    }
    
    

    执行结果:
    在这里插入图片描述
    开始读操作,线程可以都进行读操作,要是有写操作,会等读操作都完成.

    Lock和synchronized的选择
    总的来说,Lock和synchronized有以下几点不同:
    (1) Lock是一个接口,是JDK层面的实现;而synchronized是Java中的关键字,是Java的内置特性,是JVM层面的实现;

    (2) synchronized 在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;而Lock在发生异常时,如果没有主动通过unLock()去释放锁,则很可能造成死锁现象,因此使用Lock时需要在finally块中释放锁;

    (3) Lock 可以让等待锁的线程响应中断,而使用synchronized时,等待的线程会一直等待下去,不能够响应中断;

    (4) 通过Lock可以知道有没有成功获取锁,而synchronized却无法办到;

    (5) Lock可以提高多个线程进行读操作的效率。

    在性能上来说,如果竞争资源不激烈,两者的性能是差不多的。而当竞争资源非常激烈时(即有大量线程同时竞争),此时Lock的性能要远远优于synchronized。所以说,在具体使用时要根据适当情况选择。

    世界上所有的不公平都是由于当事人能力不足造成的.
  • 相关阅读:
    《手把手教你》系列技巧篇(三十二)-java+ selenium自动化测试-select 下拉框(详解教程)
    《手把手教你》系列技巧篇(三十一)-java+ selenium自动化测试- Actions的相关操作-番外篇(详解教程)
    《手把手教你》系列技巧篇(三十)-java+ selenium自动化测试- Actions的相关操作下篇(详解教程)
    《手把手教你》系列技巧篇(二十九)-java+ selenium自动化测试- Actions的相关操作上篇(详解教程)
    ApplicationContext在非Service类中调用Spring的Serivce类
    java多字段排序
    PropertyDescriptor动态setter和getter设置对象属性
    presto timestmp使用
    【效能提升】我们排查一个bug的过程是怎么样的?
    【效能提升】上线前漏了SQL脚本,漏加上某个配置项了?
  • 原文地址:https://www.cnblogs.com/javayida/p/13347036.html
Copyright © 2011-2022 走看看