Java synchronized 关键字 可以将一个代码块或一个方法标记为同步代码块。同步代码块是指同一时间只能有一个线程执行的代码,并且执行该代码的线程持有同步锁。synchronized关键字可以作用于

  • 一个代码块
  • 一种方法

当一个方法或代码块被声明为synchronized时,如果一个线程正在执行该synchronized 方法或代码块,其他线程会被阻塞,直到持有同步锁的线程释放。根据锁定的范围可以分为

  • 类级别的锁可以防止多个线程在运行时同时进入该类所有实例化对象的 synchronized代码块中。
  • 对象级别的锁可以防止多个线程在运行时同时进入当前(或某一个)实例化对象的 synchronized代码块中。

1. 对象级别的同步锁

对象级别的同步锁:当我们想要在多线程环境下同步执行一个非静态方法或非静态代码块时,在类的方法或代码块加上synchronized关键字,可以保证对象实例级别数据的线程安全。(比较后文的类级别的同步锁,回头来理解这句话)

对象级别的加锁的代码如下,如:在方法上加锁,锁对象为当前类的实例化对象

public class DemoClass{
public synchronized void demoMethod(){}
}

如:为代码块加锁,锁对象为this对象

public class DemoClass{
public void demoMethod(){
synchronized (this){
//同步代码块
}
}
}

如:为代码块加锁,锁对象为我们创建的任意一个对象。不要使用非final的成员变量作为同步锁对象,因为非final成员变量可以被重新赋值,导致不同的线程使用不同的对象作为锁,达不到同步锁定的效果。

public class DemoClass{
//注意这里的关键字final非常重要,看说明
private final Object lock = new Object();
public void demoMethod(){
synchronized (lock){
//同步代码块
}
}
}

2. 类级别的同步锁

类级别的锁可以防止多个线程在运行时进入该类所有实例化对象的 "synchronized块中。也就是说如果运行时有100个DemoClass的实例,那么每次只有一个线程能够在任何一个实例中执行demoMethod(),所有其他实例的所有其他线程都被锁定。

为了保障静态数据线程安全,应该使用类级别的锁定。我们知道static关键字将方法的数据关联到类的级别上,所以在静态方法上使用锁。

静态方法加锁,对该类所有的实例化对象生效

public class DemoClass{
//静态方法加锁,对该类所有的实例化对象生效
public synchronized static void demoMethod(){ }
}

获取 .class类的引用,类级别的锁

public class DemoClass{
public void demoMethod(){
//获取 .class类的引用,类级别的锁,对该类所有的实例化对象生效
synchronized (DemoClass.class){
//同步代码块
}
}
}

使用静态对象的锁,类级别的锁

public class DemoClass{
//静态对象,类级别,注意这里的关键字final非常重要
private final static Object lock = new Object();
public void demoMethod(){
//使用静态对象的锁,类级别锁,对该类所有的实例化对象生效
synchronized (lock){
//同步代码块
}
}
}

3. 总结

  1. Java中的同步机制保证了两个或多个线程无法同时执行一个需要相同同步锁的方法。
  2. "synchronized "关键字只能用于方法和代码块。这些方法或代码块可以是静态非静态的。
  3. 当一个线程进入synchronized方法或代码块时,它就会获得一个锁,当它离开同步方法或代码块时,它就会释放这个锁。如果线程执行过程出现任何错误或异常,锁也会被释放。
  4. 使用"synchronized "关键字持有的锁在本质上是可重入的,这意味着如果一个同步方法调用另一个使用相同锁的同步方法,那么持有锁的当前线程可以进入该方法而无需再次获得锁。
  5. 如果同步块中使用的对象为空,Java synchronized 将抛出NullPointerException
  6. 使用synchronized同步方法会给你的应用程序带来性能成本。因此,尽量在绝对需要的情况下才使用同步。另外优先考虑使用同步代码块,并且只同步代码的关键部分。
  7. 静态同步方法和非静态同步方法有可能同时或并发运行,因为它们使用的是不同的锁。
  8. 根据Java语言规范,你不能在构造函数中使用synchronized关键字。这是不合法的,会导致编译错误。
  9. 不要使用非final的成员变量作为同步锁对象,因为非final成员变量可以被重新赋值,导致不同的线程使用不同的对象作为锁,达不到同步锁定的效果。
  10. 不要使用字符串字面量作为锁对象,如:String a = "1";,因为它们可能会被应用程序中的其他地方引用,并可能导致死锁。用new关键字创建的字符串对象可以安全使用。

欢迎关注我的博客,里面有很多精品合集

  • 本文转载注明出处(必须带连接,不能只转文字):字母哥博客

觉得对您有帮助的话,帮我点赞、分享!您的支持是我不竭的创作动力! 。另外,笔者最近一段时间输出了如下的精品内容,期待您的关注。

Java synchronized对象级别与类级别的同步锁的更多相关文章

  1. 理解Java中对象基础Object类

    一.Object简述 源码注释:Object类是所有类层级关系的Root节点,作为所有类的超类,包括数组也实现了该类的方法,注意这里说的很明确,指类层面. 所以在Java中有一句常说的话,一切皆对象, ...

  2. Java匿名对象和匿名类总结

    一.匿名对象 匿名对象是没有名字的实体,也就是该实体没有对应的变量名引用  匿名对象的特征:            创建的匿名类的对象只能够调用一次            匿名对象只在堆内存中开辟空间 ...

  3. Java Synchronized的用法

    synchronized是Java中的关键字,是一种同步锁.它修饰的对象有以下几种: 1. 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码 ...

  4. JAVA Synchronized (一)

    <编程思想之多线程与多进程(1)——以操作系统的角度述说线程与进程>一文详细讲述了线程.进程的关系及在操作系统中的表现,这是多线程学习必须了解的基础.本文将接着讲一下Java线程同步中的一 ...

  5. Java多线程同步锁的理解

    java主要通过synchronized的关键字来实现的.让我们从一个买票程序说起吧. package com.day04; /** * * @author Administrator 问题描述:使用 ...

  6. 对象级别锁 vs 类级别锁 – Java

    同步针对的是多线程.同步的方法或代码块同时只能由一个线程执行. Java支持多线程来执行.这可能会导致两个或多个线程访问同一个字段或对象.同步是一个使所有并发执行的线程同步的过程.同步避免了由于共享内 ...

  7. 对象级别锁 vs 类级别锁(Java)

    前言 对于多线程(并发)和Spring Boot这两块在同步进行学习中,在看到使用synchronized关键字使操作同步时,看到和C#中不一样的东西,所以这里呢,就深入学习了下,若有错误之处,还望指 ...

  8. synchronized 线程同步-类级别锁定

    1.demo 说明:代码中通过 printNum 方法传入参数判断 a.b 分别对 num 这个参数的值进行了修改. package demo1; import sun.applet.Main; pu ...

  9. jQuery插件开发全解析,类级别与对象级别开发

    jQuery插件的开发包括两种: 一种是类级别的插件开发,即给jQuery添加新的全局函数,相当于给jQuery类本身添加方法.jQuery的全局函数就是属于jQuery命名空间的函数,另一种是对象级 ...

随机推荐

  1. Cannot load driver class: com.mysql.jdbc.Driver

    mysql-connector-java提供了mysql驱动等类库,此处必须引入此依赖,否则将会提示: Cannot load driver class: com.mysql.jdbc.Driver等 ...

  2. 使用C#进行数据库增删改查ADO.NET(一)

    这节讲一下如何使用C#进行数据库的增删改查操作,本节以SQL Server数据库为例. .NET 平台,使用ADO.NET 作为与数据库服务器的桥梁,我们通过ADO.NET就可以使用C#语言操作数据库 ...

  3. JUC 并发类概览

    JUC 并发类及并发相关类概览,持续补充... AQS 内部有两个队列,一个等待队列(前后节点),一个条件队列(后继节点),其实是通过链表方式实现: 等待队列是双向链表:条件队列是单向链表:条件队列如 ...

  4. SparkSQL电商用户画像(五)之用户画像开发(客户基本属性表)

    7.电商用户画像开发 7.1用户画像--数据开发的步骤 u 数据开发前置依赖 -需求确定 pv uv topn -建模确定表结构 create table t1(pv int,uv int,topn ...

  5. Python数模笔记-NetworkX(2)最短路径

    1.最短路径问题的常用算法 最短路径问题是图论研究中的经典算法问题,用于计算图中一个顶点到另一个顶点的最短路径. 1.1 最短路径长度与最短加权路径长度 在日常生活中,最短路径长度与最短路径距离好像并 ...

  6. multiset容器erase函数的误用

    <从缺陷中学习C/C++>第3章库函数问题,本章主要介绍库函数的使用中会遇到的问题.使用库函数可以降低软件开发的难度,提高代码编写的效率.本节为大家介绍multiset容器erase函数的 ...

  7. Spring Cloud Gateway之全局过滤器在工作中的使用场景

    一.使用注意事项 1.全局过滤器作用于所有的路由,不需要单独配置. 2.通过@Order来指定执行的顺序,数字越小,优先级越高. 二.默认全局拦截器的整体架构 三.实战场景,例如,校验token.记录 ...

  8. CF1444A Division 求质因数的方法

    2020.12.20 求质因数的方法 CF1444A Division #include<bits/stdc++.h> #define ll long long #define fp(i, ...

  9. 用户添加到sudoer列表## Allow root to run any commands anywhere root ALL=(ALL) ALL Iron ALL=(ALL) ALL

    将用户添加到sudoer列表 李序锴关注 2017.12.20 15:03:25字数 605阅读 4,067 默认情况下,linux没有将当前用户列入到sudoer列表中(在redhat系列的linu ...

  10. linux自动化交互脚本expect详解set timeout 5是 意思是在expect语句中,5s后超时,不再作出选择。

    linux自动化交互脚本expect详解  更新时间:2020年10月21日 10:13:20   作者:lendsomething     这篇文章主要介绍了linux自动化交互脚本expect的相 ...