• 锁机制


    1.锁是干什么用的
      锁一般来说用作资源控制,限制资源访问,防止在并发环境下造成数据错误

    2.重入锁
      重入锁也叫作递归锁,指的是同一个线程外层函数获取到一把锁后,内层函数同样具有这把锁的控制权限
      synchronized和ReentrantLock就是重入锁对应的实现
      synchronized重量级的锁 
      ReentrantLock轻量级的锁 lock()代表加入锁 unlock()代表释放锁

      不可重入锁:说明当没有释放该锁时。其他线程获取该锁会进行等待

    复制代码
    public class MyLock {
        //标识锁是否可用  如果值为 true代表有线程正在使用该 锁 ,如果为false代表没有人使用锁
        private boolean isLocked=false;
        //获取锁:加锁
        public synchronized void lock() throws InterruptedException {
            //判断当前该锁是否正在使用
            while (isLocked){
                wait();
            }
            //当前没有人使用情况 下就占用该锁
            isLocked=true;
        }
    
        //释放锁
        public synchronized  void unLock(){
            //将当前锁资源释放
            isLocked=false;
            //唤起正在等待使用锁的线程
            notify();
        }
    
    }
    复制代码
    复制代码
    public class MyLockTest {
    MyLock myLock=new MyLock();
        //A业务
        public void print() throws InterruptedException {
            //获取一把锁
            myLock.lock();
            System.out.println("print业务方法");
            doAdd();
            //释放锁
            myLock.unLock();
        }
        //B业务方法
        public void  doAdd() throws InterruptedException {
            //获取一把锁
            myLock.lock();
            System.out.println("aoAdd方法");
            //释放锁
            myLock.unLock();
    
        }
    
        public static void main(String[] args) throws InterruptedException {
            MyLockTest myLockTest=new MyLockTest();
            myLockTest.print();
        }
    }
    复制代码

      控制台结果:

    当前效果就造成了死锁

      synchronized可重入性:如果当前A持有一把锁,在A业务内部调用B,那么B也同样拥有这把锁的使用权限

      编写测试代码:

    复制代码
    MyLock myLock=new MyLock();
        //A业务
        public synchronized void print() throws InterruptedException {
    
            System.out.println("print业务方法");
            doAdd();
    
        }
        //B业务方法
        public synchronized void  doAdd() throws InterruptedException {
    
            System.out.println("aoAdd方法");
    
    
        }
    
        public static void main(String[] args) throws InterruptedException {
            MyLockTest myLockTest=new MyLockTest();
            myLockTest.print();
        }
    复制代码

      控制台结果:

      ReentrantLock同样具有可重入性

      编写测试代码:

    复制代码
    public class MyLockTest {
        //创建锁对象
        Lock lock=new ReentrantLock();
        //A业务
        public void print() throws InterruptedException {
            //获取了一把锁
            lock.lock();
            System.out.println("print业务方法");
            doAdd();
            //释放锁
            lock.unlock();
    
        }
        //B业务方法
        public void  doAdd() throws InterruptedException {
            //获取一把锁
            lock.lock();
            System.out.println("aoAdd方法");
            //释放锁
            lock.unlock();
    
        }
    
        public static void main(String[] args) throws InterruptedException {
            MyLockTest myLockTest=new MyLockTest();
            myLockTest.print();
        }
    }
    复制代码

      控制台结果:

    3. 读写锁

      并发线程下,所有线程都执行读的操作,会不会有问题
      并发线程下,部分读部分写会不会有问题 会发生写冲突
      并发线程下,所有线程都执行写会不会有问题 会发生写冲突

      编写测试代码:

    复制代码
     //创建一个集合
        static Map<String,String> map=new HashMap<String,String>();
        //创建一个读写锁
        static ReentrantReadWriteLock lock=new ReentrantReadWriteLock();
        //获取读锁
        static Lock readLock=lock.readLock();
        //获取写锁
        static Lock writeLock=lock.writeLock();
        //写操作
        public Object put(String key,String value){
            writeLock.lock();
            try {
                System.out.println("Write正在执行写操作~");
                Thread.sleep(100);
                String put = map.put(key, value);
                System.out.println("Write写操作执行完毕~");
                return put;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                writeLock.unlock();
            }
            return null;
    
        }
    
        //写操作
        public Object get(String key){
            readLock.lock();
            try {
                System.out.println("Read正在执行读操作~");
                Thread.sleep(100);
                String value = map.get(key);
                System.out.println("Read读操作执行完毕~");
                return value;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                readLock.unlock();
            }
            return null;
    
        }
    
        public static void main(String[] args) {
            ReadWriteLock lock=new ReadWriteLock();
            for (int i = 0; i < 10; i++) {
                int finalI = i;
                new Thread(()->{
                    try {
                        //写操作
                        lock.put(finalI +"","value"+finalI);
                        //读操作
                        System.out.println(lock.get(finalI+""));
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }).start();
            }
    
        }
    复制代码

      控制台 结果:

    我们可以看出是当所有写操作都执行完毕后才开始执行读操作

    4. 乐观锁

      总认为不会发生并发问题,每一次取数据时总认为其他线程不会对该数据先进性更改,但是在更新时会判断其他线程在这之前有

      没有对该数据进行修改,
      数据库当中常用方案:版本号控制

    5.悲观锁
      总是假设最坏的情况,每次取数据时,都会认为其他线程会对该数据进行修改,所以会进行加锁
      其他线程访问的时候会阻塞等待,例如在数据库当中可以使用行锁,表锁以及读写锁等方式实现

  • 相关阅读:
    你要结婚了丶
    20150806这是个悲伤的日子。
    今天是我的生日。
    这是从word发的第一篇博客。
    【关于JavaScript】自动计算的实例
    【关于JavaScript】常见表单用户名、密码不能为空
    【关于php】Appserv中关于DW配置站点问题
    【关于php】Appserv的安装注意事项
    【无题】写在5月18日
    HTML中如何添加日历插件(JQUERY)
  • 原文地址:https://www.cnblogs.com/tinghao/p/12567786.html
Copyright © 2020-2023  润新知