• Synchronized同步锁


    一、什么是Synchronized?

           Synchronized同步锁,简单来说,使用Synchronized关键字将一段代码逻辑,用一把锁给锁起来,只有获得了这把锁的线程才访问。并且同一时刻,只有一个线程能持有这把锁,这样就保证了同一时刻只有一个线程能执行被锁住的代码,从而确保代码的线程安全。

    二、什么是锁?

            每个Java对象都可以充当一个实现同步的锁,这些锁被称为内置锁或者监视器锁。

    1. synchronized(reference-to-lock) {
    2. //临界区
    3. }

    解释:reference-to-lock就是锁的引用,任何一个Java对象都可以成为reference-to-lock.你可以实例化一个Object对象,将它作为锁。如果直接使用this,代表是当前对象作为锁。

             Synchronized关键字的用法:

    一、修饰实例方法

    synchronized修饰实例方法,用到的锁,默认为this当前方法调用对象;

    •   使用当前对象this充当锁,完成对当前方法的锁定,只有获取this锁的线程草能访问当前方法;
    • 并发过程中,同一时刻,可以有N个线程请求执行方法,但是只有一个线程可以持有this锁,才能执行;
    • 不同的线程,持有的对象,必须相同;

    当使用synchronized修饰静态方法时,以下两种写法作用和意义相同:

    1. public class Foo {
    2. // 实例方法
    3. public synchronized void doSth1() {
    4. // 获取this锁,才能执行该方法
    5. }
    6. // 实例方法
    7. public void doSth2() {
    8. synchronized(this) {
    9. // 获取this锁,才能执行该代码块
    10. }
    11. }
    12. }
    1. public static void main(String[] args) {
    2. // 实例化一个对象
    3. Foo fa = new Foo();
    4. // 创建不同的线程1
    5. Thread thread01 = new Thread() {
    6. public void run() {
    7. // 使用相同的对象访问synchronized方法
    8. fa.doSth1();
    9. }
    10. };
    11. // 创建不同的线程2
    12. Thread thread02 = new Thread() {
    13. public void run() {
    14. // 使用相同的对象访问synchronized方法
    15. fa.doSth1();
    16. }
    17. };
    18. // 启动线程
    19. thread01.start();
    20. thread02.start();
    21. }

    二、修饰静态方法:synchronized修饰静态方法,用到的锁,默认为Class对象;

    •  使用当前对象的Class对象充当锁,完成对当前方法的锁定,只有获取Class锁的线程才能访问当前方法;
    • 不同线程,持有的对象,可以不同,但必须相同类型的Class;

    1. public static void main(String[] args) {
    2. // 创建不同的对象(相同类型)
    3. Foo fa = new Foo();
    4. Foo fb = new Foo();
    5. // 创建不同线程1
    6. Thread thread01 = new Thread() {
    7. public void run() {
    8. // 使用不同的对象访问synchronized方法
    9. fa.doSth2();
    10. }
    11. };
    12. // 创建不同线程2
    13. Thread thread02 = new Thread() {
    14. public void run() {
    15. // 使用不同的对象访问synchronized方法
    16. fb.doSth2();
    17. }
    18. };
    19. // 启动线程
    20. thread01.start();
    21. thread02.start();
    22. }
    1. public class Foo {
    2. // 静态方法
    3. public synchronized static void doSth1() {
    4. // 获取当前对象的Class对象锁,才能执行该方法
    5. }
    6. // 实例方法
    7. public static void doSth2() {
    8. synchronized(this.getClass()) {
    9. // 获取当前对象的Class对象锁,才能执行该代码块
    10. }
    11. }
    12. }

     三、synchronized修饰代码块

    1. synchronized(自定义对象) {
    2. //临界区
    3. }

    三、Synchronized关键字的补充 

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

                在没有枷锁的情况下,所有的线程都可以自由的访问对象中的代码,而synchronized关键字只是限制了线程对于其他已经枷锁的同步代码块的访问,并不会对其他代码做限制。所以,同步代码块应该是越小越好。

    • 父类中synchronized修饰的方法,如果子类没有重写,则该方法仍然是线程安全性;如果子类重写,并且没有使用Synchronized修饰,则该方法不是线程安全的;
    • 在定义接口方法时,不能使用synchronized关键字;
    • 构造方法不能使用synchronized关键字(因为此时的构造代码块还没有对象),但可以使用synchronized代码块来进行同步;
    • 离开同步代码块后,所获得的锁会被自动释放;

  • 相关阅读:
    Prometheus Pushgateway简介(二)
    Spring MVC统一异常处理的3种方式(附带实例)
    李白的苏台览古译文赏析
    sqli-labs-master安装及报错处理
    基于java小型银行管理系统计算机毕业设计源码+系统+lw文档+mysql数据库+调试部署
    Shell命令切换root用户、管理配置文件、检查硬件
    Pytorch搭建AlexNet 预测实现
    推荐算法中CTR和CVR的ESMM模型pytorch实现
    【Pytorch】深度学习之优化器
    3.SpringBoot整合持久层技术
  • 原文地址:https://blog.csdn.net/qq_49194786/article/details/126768458