如何证明synchronized是可重入锁,以及和lock公平非公平锁

synchronized可重入锁的实现原理:
synchronized底层的实现原理是利用计算机系统的mutex Lock实现。每一个可重入锁都会关联一个线程ID和一个锁状态status。
当一个线程请求方法时,会去检查锁状态,如果锁状态是0,代表该锁没有被占用,直接进行CAS操作获取锁,将线程ID替换成自己的线程ID。如果锁状态不是0,代表有线程在访问该方法。此时,如果线程ID是自己的线程ID,如果是可重入锁,会将status自增1,然后获取到该锁,进而执行相应的方法。如果是非重入锁,就会进入阻塞队列等待。
释放锁时,可重入锁,每一次退出方法,就会将status减1,直至status的值为0,最后释放该锁。
释放锁时,非可重入锁,线程退出方法,直接就会释放该锁。

所以,从一定程度上来说,可重入锁可以避免死锁的发生。
————————————————
原文链接:

https://blog.csdn.net/qq_39839075/article/details/100055872

代码证明:

package com.special.threademo.concurrency.synchcriozed;

/**
 * @author liuYC
 * @ClassName ReenTrantDemo
 * @Description TODO
 * @date 2021/7/20 16:17
 * 说明:因为synchronized的作用在class上,当调用test1()中再次调用test2(),即证明了是可以重入的
 */
public class ReenTrantDemo {
    public static void main(String[] args) {
        System.out.println("start -------");
        ReenTrantDemo.test1();
        System.out.println("end -------");

    }

    public static synchronized void test1() {
        System.out.println("test 1");
        test2();
    }

    public static synchronized void test2() {
        System.out.println("test 2 ");
//        test2();
    }
}

结论:

当一个线程访问对象的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该对象中的非synchronized(this)同步代码块。

原因:

标记在对应的实例方法上和对应的 class 的区别!:从对象和类的分配位置说起:深度探索c++对象模型

很有可能不会加载,等到使用到的时候才会加载.

证明公平锁与否:

结论:

        synchronized非公平锁:

公平锁:

获取不到锁的时候,会自动加入队列,等待线程释放后,队列的第一个线程获取锁

非公平锁:

获取不到锁的时候,会自动加入队列,等待线程释放锁后所有等待的线程同时去竞争

        lock可指定公平与否

更加锁的可操作性、可中断的获取锁以及超时获取锁等多种synchronized不具备的特性。

注释基本明确,就不多说了。wait和notify是配合synchronized使用,await和signal是配合lock使用,区别在于唤醒时notify不能指定线程唤醒,signal可以唤醒具体的线程,更小的粒度控制锁。

代码展示:

package com.special.threademo.concurrency.synchcriozed;

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

/**
 * @author liuYC
 * @ClassName ReentrantFairDemo
 * @Description TODO
 * @date 2021/7/20 16:42
 * 公平锁三个线程依次获取锁进行购票
 */
public class ReentrantFairDemo {

    //总票数
    private int count = 10;

    //创建锁 ReentrantLock可实现公平锁与非公平锁
    private Lock reentrantLock = new ReentrantLock(true);
//    private Lock reentrantLock = new ReentrantLock();// 非公平锁

    /* //获取余票数量方法
     public void getCount() {
         while (true) {
             //锁住
             reentrantLock.lock();
             if (count > 0) {
                 try {
                     Thread.sleep(1000);
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 }
                 count--;
                 System.out.println(Thread.currentThread().getName() + "卖票成功,余票为:" + count);
             }
             reentrantLock.unlock();
         }

     }*/
    //获取余票数量方法:
    // 证明的逻辑就是1234个线程顺序启动但是购票顺序却不一样,意味着获得锁的公平性不一样,所以非公平锁
    // 且执行多次的顺序是不一样的:

    /**
     * 1卖票成功,余票为:9
     * 4卖票成功,余票为:8
     * 3卖票成功,余票为:7
     * 2卖票成功,余票为:6
     * <p>
     * <p>
     * demo2
     * private static class DiningRoom {
     * //获取食物
     * public void getFood() {
     * System.out.println(Thread.currentThread().getName()+":排队中");
     * synchronized (this) {
     * System.out.println(Thread.currentThread().getName()+":@@@@@@打饭中@@@@@@@");
     * }
     * }
     * }
     * 为什么执行多次都一样,难道说线程不够多么?
     */

    /**
     * 没有加上对应的静态内部类的运行结果
     * 1:排队中
     * 1:@@@@@@打饭中@@@@@@@
     * 2:排队中
     * 2:@@@@@@打饭中@@@@@@@
     * 3:排队中
     * 3:@@@@@@打饭中@@@@@@@
     * 4:排队中
     * 4:@@@@@@打饭中@@@@@@@
     * 5:排队中
     * 5:@@@@@@打饭中@@@@@@@
     * 6:排队中
     * 6:@@@@@@打饭中@@@@@@@
     */
//    获取食物d 注意静态内部类才有这个效果:原因就是因为锁在class上面????????????????????
    private static class d2 {
        /**
         * 加上对应的静态内部类的运行结果
         * 同学编号:001:排队中
         * 同学编号:002:排队中
         * 同学编号:001:@@@@@@打饭中@@@@@@@
         * 同学编号:003:排队中
         * 同学编号:002:@@@@@@打饭中@@@@@@@
         * 同学编号:004:排队中
         * 同学编号:003:@@@@@@打饭中@@@@@@@
         * 同学编号:004:@@@@@@打饭中@@@@@@@
         * 同学编号:005:排队中
         * 同学编号:005:@@@@@@打饭中@@@@@@@
         */
        public void getCount() {
            System.out.println(Thread.currentThread().getName() + ":排队中");
            synchronized (this) {
                System.out.println(Thread.currentThread().getName() + ":@@@@@@打饭中@@@@@@@");
            }
        }
    }

    /**
     * 1排队中
     * 2排队中
     * 3排队中
     * 4排队中
     * 5排队中
     * 6排队中
     * 1卖票成功,余票为:9
     * 6卖票成功,余票为:8
     * 5卖票成功,余票为:7
     * 4卖票成功,余票为:6
     * 3卖票成功,余票为:5
     * 2卖票成功,余票为:4
     *
     * @param
     */
    public void getCount() {
        //锁住 去掉while否则循环的结果是第一个线程一直在持有进行执行。
        System.out.println(Thread.currentThread().getName() + "排队中");
        synchronized (this) {
            if (count > 0) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                count--;
                System.out.println(Thread.currentThread().getName() + "卖票成功,余票为:" + count);
            }
        }

    }

    public static void main(String[] args) {
        ReentrantFairDemo d = new ReentrantFairDemo();
        final d2 dd22 = new d2();

        //第1个线程
        new Thread(new Runnable() {
            @Override
            public void run() {
                d.getCount();
            }
        }, "1").start();

        //第2个线程
        new Thread(new Runnable() {
            @Override
            public void run() {
                d.getCount();
            }
        }, "2").start();

        //第33个线程
        new Thread(new Runnable() {
            @Override
            public void run() {
                d.getCount();
            }
        }, "3").start();
        //第4个线程
        new Thread(new Runnable() {
            @Override
            public void run() {
                d.getCount();
            }
        }, "4").start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                d.getCount();
            }
        }, "5").start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                d.getCount();
            }
        }, "6").start();
        // 创建线程的第二种方式:存在的原因:主要是为了验证,为什么执行的逻辑这么奇怪
        for (int i = 0; i < 5; i++) {
            new Thread(() -> {
                dd22.getCount();
            }, "同学编号:00" + (i + 1)).start();
        }
    }

}

问题为什么要用静态内部类才有这个效果:原因就是因为锁在class上面

否则没有明显的证据表明,随机的效果:

但是为什么只有这样才可以证明,如果那我不用这个呢?

存在队列的相关性顺序基本是:165432,无论运行多少次都这样

——————————

参考资料:

参考链接

synchronized是公平锁还是非公平锁

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

specialApe

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值