墨风如雪博客

  • 源码小店
  • 导航站
  • 登录
  • java
  • 资源分享
让AI使用变得如此简单
  1. 首页
  2. java
  3. 正文

Java中synchronized关键字的八个锁问题及解决办法

2023年 5月 2日 188点热度 0人点赞 0条评论

八个锁问题

当多个线程访问同一个对象的synchronized方法时,可能会产生八种不同的锁问题:

  1. 对于普通同步方法,锁是当前实例对象。
  2. 对于静态同步方法,锁是当前类的Class对象。
  3. 对于同步方法块,锁是synchronized括号里配置的对象。
  4. 对于一个普通方法,即非同步方法,不会产生锁问题,不需要等待锁,直接访问方法即可。
  5. 对于一个静态方法,即使非同步方法,也会存在锁问题。因为静态方法是属于类的,而不是属于实例的,所以静态方法的锁是当前类的Class对象。
  6. 当一个线程执行的代码出现异常时,锁会被自动释放。
  7. synchronized锁住的代码块不是原子操作。如果同一个线程执行两次synchronized代码块,它将获得锁两次。
  8. 如果两个及以上线程同时等待某个monitor对象,那么只有一个线程可以继续执行,其他线程将被阻塞。

解决办法

下面分别对八个锁问题给出相应的解决办法。

1. 对于普通同步方法,锁是当前实例对象。

解决办法是在方法前面加上synchronized关键字。

public synchronized void add(){...}

2. 对于静态同步方法,锁是当前类的Class对象。

解决办法是在方法前面加上synchronized关键字,同时锁定当前类。

public static synchronized void add(){...}

3. 对于同步方法块,锁是synchronized括号里配置的对象。

解决办法是在同步代码块前面加上synchronized关键字,同时锁定指定的对象。例如:

public void add(){
    synchronized(lock){
        ...
    }
}

4. 对于普通非同步方法,不会产生锁问题,无需解决。

直接访问即可。

5. 对于静态非同步方法,也会存在锁问题。

解决办法是锁定当前类的Class对象,可以使用synchronized(Class)。

public static void add(){
    synchronized(ClassName.class){
        ...
    }
}

6. 当一个线程执行的代码出现异常时,锁会被自动释放。

无需解决,JVM会自动释放锁。

7. synchronized锁住的代码块不是原子操作。

解决办法是使用同步方法而不是同步代码块。

public synchronized void add(){
    ...
}

8. 如果两个及以上线程同时等待某个monitor对象,那么只有一个线程可以继续执行,其他线程将被阻塞。

解决办法是通过使用notify()或者notifyAll()通知等待线程,从而释放对象锁。

public synchronized void add(){
    ...
    notify();
}

下面是一个使用synchronized解决八个锁问题的示例代码:

public class MyObject {
    private static int count1 = 0;
    private int count2 = 0;
    private Object lock = new Object();

    public static synchronized void method1() {
        // 锁定当前类,等价于 synchronized(MyObject.class)
        System.out.println("Method 1 start");
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Method 1 end");
    }

    public synchronized void method2() {
        // 锁定当前实例对象,等价于 synchronized(this)
        System.out.println("Method 2 start");
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Method 2 end");
    }

    public void method3() {
        // 锁定指定对象
        synchronized (lock) {
            System.out.println("Method 3 start");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Method 3 end");
        }
    }

    public static void method4() {
        // 锁定当前类,等价于 synchronized(MyObject.class)
        synchronized (MyObject.class) {
            System.out.println("Method 4 start");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Method 4 end");
        }
    }

    public static synchronized void method5() {
        // 锁定当前类,等价于 synchronized(MyObject.class)
        count1++;
        System.out.println("Method 5 count1=" + count1);
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public synchronized void method6() {
        // 锁定当前实例对象,等价于 synchronized(this)
        count2++;
        System.out.println("Method 6 count2=" + count2);
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void method7() {
        // 锁定当前类,等价于 synchronized(MyObject.class)
        synchronized (MyObject.class) {
            System.out.println("Method 7 start");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Method 7 end");
        }
    }

    public static synchronized void method8() {
        // 锁定当前类,等价于 synchronized(MyObject.class)
        System.out.println("Method 8 start");
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Method 8 end");
    }
}
本作品采用 知识共享署名 4.0 国际许可协议 进行许可
标签: java synchronized 八个锁问题 解决办法
最后更新:2023年 5月 2日

墨风如雪

一个热爱生活,热爱分享的程序员

打赏 点赞
< 上一篇
下一篇 >

文章评论

您需要 登录 之后才可以评论

墨风如雪

一个热爱生活,热爱分享的程序员

最新 热点 随机
最新 热点 随机
智谱AI掀桌子了:那个会“思考”的视觉模型,9B参数硬刚72B巨兽 AI开口“飚”方言!阿里Qwen-TTS发布,从京腔到川普,7种宝藏音色任你选 华为亮出王牌:70亿参数“特种兵”与720亿“航母”级模型同时开源 一张3090就能跑!腾讯混元A13B,这是给AI圈的降维打击? 告别抓耳挠腮!Gemini CLI,让你和你的终端聊上了天 AI圈大地震!120亿参数的FLUX编辑器开源,你的显卡准备好了吗?
Kimi-Dev-72B:月之暗面如何用720亿参数“驯服”代码世界?国产视频AI卷出新高度!海螺02不止能跳舞,还懂物理腾讯云掀桌子了!这个免费CDN,国内秒开还无限流量?别只盯着Suno了,腾讯端出的这盘“王炸”可能要改变游戏规则Kimi变身学术“卷王”,你的论文和报告还好吗?昆仑万维扔出王炸:32B模型干翻671B,代码界迎来全能修理工!
java 数据库连接池技术 HikariCP的(超详细总结) 每日一道算法题:环形链表详解 java 数据库连接池技术Apache Commons DBCP的(超详细总结) 网络传输当中 五种IO模型详解 Java多线程编程中的ReentrantLock详解 gpt4free 最新部署教程! 我们在VPS上 通过Docker 来进行安装
标签聚合
deepseek 算法 动态规划 设计模式 教程 spring AI java

COPYRIGHT © 2023 墨风如雪博客. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang

免责声明 - 隐私政策