当前位置: 首页 > news >正文

Java基础之:线程可重入锁,公平锁,非公平锁

其实在聊线程的锁(synchronized和lock)现在再补充一些东西,比如可重入锁,公平锁。

可重入锁

其实synchronized(隐式)和Lock(显示)两中锁其实都是可重入。

其实这个听着很神奇,用一个简单的例子来说就是,比如如果一座大楼锁门了,然后在里面的人还是可以随便在公司中打开公司大门的锁的,而公司门锁了里面的人自然可以在房间里面随便打开锁然后进去。说白了这个就是一个”套锁“的现象所以可重入锁又被称为递归锁

在这里插入图片描述

其实这个说白了就是,你锁住了最外面一层,里面所以加锁等操作了。

还是老规矩演示:

public class test {

    public static void main(String[] args) {
//        前面聊过锁到底锁什么,所以就随便弄一个锁的对象,没有什么具体意义
        Object obj = new Object();
//        这里用lambda表达式,如果不懂可以翻看一下前面我的文章
        new Thread(() -> {
            synchronized (obj) {
                System.out.println("写字楼大门锁");

                synchronized (obj) {
                    System.out.println("公司大门锁");
                    synchronized (obj) {
                        System.out.println("房间大门锁");

                    }
                }

            }
        }).start();

    }
}

看一下结果

在这里插入图片描述

这个可重入锁使用synchronized还好会自动释放锁,但是使用lock的话会有一个一些要注意的点。不过还是老规矩,用lock在重现上面的代码一次。

public class test {

    public static void main(String[] args) {
        Lock lock = new ReentrantLock();
//        这里用lambda表达式,如果不懂可以翻看一下前面我的文章
        new Thread(() -> {
            lock.lock();
            try {
                System.out.println("写字楼大门锁");

                lock.lock();
                try {
                    System.out.println("公司大门锁");
                    lock.lock();
                    try {
                        System.out.println("房间大门锁");

                    } finally {
                        lock.unlock();
                    }
                } finally {
                    lock.unlock();
                }

            } finally {
                lock.unlock();
            }
        }).start();

    }
}



在这里插入图片描述

结果一样,但是如果这样做呢,将其中的一个锁锁了然后忘了关闭,又如何?

如果最里面的一层忘了解锁(无论如何同一个lock在锁了多少次一般要解锁多少次,不然会出现错误)

演示这个:

public class test {

    public static void main(String[] args) {
        Lock lock = new ReentrantLock();
//        这里用lambda表达式,如果不懂可以翻看一下前面我的文章
        new Thread(() -> {
            lock.lock();
            try {
                System.out.println("写字楼大门锁");

                lock.lock();
                try {
                    System.out.println("公司大门锁");
                    lock.lock();
                    try {
                        System.out.println("房间大门锁");

                    } finally {
//                        如果最里面的一层忘了解锁
//                        lock.unlock();
                    }
                } finally {
                    lock.unlock();
                }

            } finally {
                lock.unlock();
            }
        }).start();
// 再次来一个线程:
        new Thread(()->{
            lock.lock();
            try{
            System.out.println("第二个次要进入");
            }finally {
                lock.unlock();
            }
        }).start();



    }
}

在这里插入图片描述

会发现无法运行第二个线程,以及程序一直处于运行状态。所以在使用lock加锁解锁的时候一定要成对出现,不然浪费性能以外还会影响其它程序的运行。

公平锁和非公平锁

公平锁和非公平锁,这个其实很好理解的,其实最重要的词语在于公平,毕竟多线程说白就是抢资源。还是老规矩,用例子来测试。

非公平锁:

  • 先用synchronized试一下:
public class test implements  Runnable {
    static Integer number=30;
    public static void main(String[] args) {
        for (int i = 0; i < 30; i++) {
            new Thread(new test(),"AA").start();
        }
        for (int i = 0; i < 30; i++) {
            new Thread(new test(),"BB").start();
        }
    }


    @Override
    public  void run() {
       synchronized (number){
         if(number>0){

             System.out.println("线程名:"+Thread.currentThread().getName()+"卖了票"+(number--)+"还剩下票数"+number);
         }}
    }
}

在这里插入图片描述

可以看出一个事情,那就是所有的票都被AA卖完了。其实聊公平和非公平锁与synchronized关系不太大,因为synchronized的锁很多时候程序员很难操作的。

  • Lock

现在用lock,可以如下看到:

 Lock lock= new ReentrantLock();

通过这个构造方法可以查看:

在这里插入图片描述

会发现再创建Lock的时候,会有两个方法,一个公平同步,一个是非公平。不带参数的为非公平锁,所以如下尝试:

public class test implements  Runnable {
    static Integer number=30;
    Lock lock= new ReentrantLock();
    public static void main(String[] args) {

        for (int i = 0; i < 30; i++) {
            new Thread(new test(),"AA").start();
        }
        for (int i = 0; i < 30; i++) {
            new Thread(new test(),"BB").start();
        }
    }


    @Override
    public  void run() {
        lock.lock();
        try{
         if(number>0){

             System.out.println("线程名:"+Thread.currentThread().getName()+"卖了票"+(number--)+"还剩下票数"+number);
         }}finally {
            lock.unlock();
        }
    }
}

在这里插入图片描述

两种方式都可以看出一件事情,那就是所有的票都被AA卖完了。

公平锁

上面说过lock在创建锁的时候可以带有参数,所以如下:

public class test implements  Runnable {
    static Integer number=30;
    Lock lock= new ReentrantLock(true);
    public static void main(String[] args) {

        for (int i = 0; i < 30; i++) {
            new Thread(new test(),"AA").start();
        }
        for (int i = 0; i < 30; i++) {
            new Thread(new test(),"BB").start();
        }
    }


    @Override
    public  void run() {
        lock.lock();
        try{
         if(number>0){

             System.out.println("线程名:"+Thread.currentThread().getName()+"卖了票"+(number--)+"还剩下票数"+number);
         }}finally {
            lock.unlock();
        }
    }
}

但是公平锁只能说是相对式公平,而不是绝对公平,看结果:

在这里插入图片描述

可以看出BB虽然也参与了卖票,但是也不是说与AA线程的平分所有卖票数据。

总结:

  • 非公平锁:

    其效率会高,毕竟疯狂的抢占资源,但是其有一个问题那就是有些线程会被饿死(也就是运行无效)

  • 公平锁:

    效率相对较低,其运行的时候只是打个招呼说有没有在等,如果人等着运行自己就开始运行,所以公平也不是绝对的公平运行所有数据。

相关文章:

  • MockServer 服务框架设计
  • 【web-利用信息泄露】(10.2)收集公布的信息、使用推论
  • java计算机毕业设计文档资料管理系统源码+系统+数据库+lw文档+mybatis+运行部署
  • JS中数组reduce()方法使用
  • 国稻种芯百团计划行动 任万军:减穴稳苗方法提高稻米品质
  • 新房IM转加私五步骤!!!
  • FPGA结构分析——ODDR,网口储备点2
  • DFS之剪枝与优化AcWing 166. 数独
  • 公司保护知识产权做法有哪些
  • Map和mybatis
  • 信息化与工业化融合,MES管理系统助力制造业发展
  • 国稻种芯百团计划行动 邓兴旺:依靠中国农业现代化的实现
  • Promethues入门,看懂不会写
  • Windows 10硬盘数据怎么永久擦除?
  • Jenkins 踩坑(四)|基于接口自动化测试完成
  • Angular2开发踩坑系列-生产环境编译
  • axios 和 cookie 的那些事
  • hadoop集群管理系统搭建规划说明
  • JS基础之数据类型、对象、原型、原型链、继承
  • Laravel5.4 Queues队列学习
  • laravel5.5 视图共享数据
  • PhantomJS 安装
  • SpiderData 2019年2月25日 DApp数据排行榜
  • spring-boot List转Page
  • 构造函数(constructor)与原型链(prototype)关系
  • 精益 React 学习指南 (Lean React)- 1.5 React 与 DOM
  • 如何正确理解,内页权重高于首页?
  • 直播平台建设千万不要忘记流媒体服务器的存在 ...
  • #etcd#安装时出错
  • $ is not function   和JQUERY 命名 冲突的解说 Jquer问题 (
  • %3cscript放入php,跟bWAPP学WEB安全(PHP代码)--XSS跨站脚本攻击
  • (2/2) 为了理解 UWP 的启动流程,我从零开始创建了一个 UWP 程序
  • (3)Dubbo启动时qos-server can not bind localhost22222错误解决
  • (delphi11最新学习资料) Object Pascal 学习笔记---第8章第5节(封闭类和Final方法)
  • (一)插入排序
  • (转)Android中使用ormlite实现持久化(一)--HelloOrmLite
  • (转)shell中括号的特殊用法 linux if多条件判断
  • (转)全文检索技术学习(三)——Lucene支持中文分词
  • (轉)JSON.stringify 语法实例讲解
  • ****** 二 ******、软设笔记【数据结构】-KMP算法、树、二叉树
  • ***监测系统的构建(chkrootkit )
  • *上位机的定义
  • 、写入Shellcode到注册表上线
  • .FileZilla的使用和主动模式被动模式介绍
  • .gitignore文件_Git:.gitignore
  • .net mvc部分视图
  • .Net Web窗口页属性
  • .Net6使用WebSocket与前端进行通信
  • .NET单元测试
  • .net使用excel的cells对象没有value方法——学习.net的Excel工作表问题
  • .Net小白的大学四年,内含面经
  • [ element-ui:table ] 设置table中某些行数据禁止被选中,通过selectable 定义方法解决
  • [3D游戏开发实践] Cocos Cyberpunk 源码解读-高中低端机性能适配策略
  • [Android]使用Git将项目提交到GitHub
  • [AutoSar]BSW_Memory_Stack_003 NVM与APP的显式和隐式同步