Java synchronized对象级别与类级别的同步锁

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. 总结
- Java中的同步机制保证了两个或多个线程无法同时执行一个需要相同同步锁的方法。
- "synchronized "关键字只能用于方法和代码块。这些方法或代码块可以是静态或非静态的。
- 当一个线程进入
synchronized方法或代码块时,它就会获得一个锁,当它离开同步方法或代码块时,它就会释放这个锁。如果线程执行过程出现任何错误或异常,锁也会被释放。 - 使用"synchronized "关键字持有的锁在本质上是可重入的,这意味着如果一个同步方法调用另一个使用相同锁的同步方法,那么持有锁的当前线程可以进入该方法而无需再次获得锁。
- 如果同步块中使用的对象为空,Java synchronized 将抛出NullPointerException
- 使用
synchronized同步方法会给你的应用程序带来性能成本。因此,尽量在绝对需要的情况下才使用同步。另外优先考虑使用同步代码块,并且只同步代码的关键部分。 - 静态同步方法和非静态同步方法有可能同时或并发运行,因为它们使用的是不同的锁。
- 根据Java语言规范,你不能在构造函数中使用
synchronized关键字。这是不合法的,会导致编译错误。 - 不要使用非final的成员变量作为同步锁对象,因为非final成员变量可以被重新赋值,导致不同的线程使用不同的对象作为锁,达不到同步锁定的效果。
- 不要使用字符串字面量作为锁对象,如:
String a = "1";,因为它们可能会被应用程序中的其他地方引用,并可能导致死锁。用new关键字创建的字符串对象可以安全使用。
欢迎关注我的博客,里面有很多精品合集
- 本文转载注明出处(必须带连接,不能只转文字):字母哥博客。
觉得对您有帮助的话,帮我点赞、分享!您的支持是我不竭的创作动力! 。另外,笔者最近一段时间输出了如下的精品内容,期待您的关注。
- 《手摸手教你学Spring Boot2.0》
- 《Spring Security-JWT-OAuth2一本通》
- 《实战前后端分离RBAC权限管理系统》
- 《实战SpringCloud微服务从青铜到王者》
- 《VUE深入浅出系列》
Java synchronized对象级别与类级别的同步锁的更多相关文章
- 理解Java中对象基础Object类
一.Object简述 源码注释:Object类是所有类层级关系的Root节点,作为所有类的超类,包括数组也实现了该类的方法,注意这里说的很明确,指类层面. 所以在Java中有一句常说的话,一切皆对象, ...
- Java匿名对象和匿名类总结
一.匿名对象 匿名对象是没有名字的实体,也就是该实体没有对应的变量名引用 匿名对象的特征: 创建的匿名类的对象只能够调用一次 匿名对象只在堆内存中开辟空间 ...
- Java Synchronized的用法
synchronized是Java中的关键字,是一种同步锁.它修饰的对象有以下几种: 1. 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码 ...
- JAVA Synchronized (一)
<编程思想之多线程与多进程(1)——以操作系统的角度述说线程与进程>一文详细讲述了线程.进程的关系及在操作系统中的表现,这是多线程学习必须了解的基础.本文将接着讲一下Java线程同步中的一 ...
- Java多线程同步锁的理解
java主要通过synchronized的关键字来实现的.让我们从一个买票程序说起吧. package com.day04; /** * * @author Administrator 问题描述:使用 ...
- 对象级别锁 vs 类级别锁 – Java
同步针对的是多线程.同步的方法或代码块同时只能由一个线程执行. Java支持多线程来执行.这可能会导致两个或多个线程访问同一个字段或对象.同步是一个使所有并发执行的线程同步的过程.同步避免了由于共享内 ...
- 对象级别锁 vs 类级别锁(Java)
前言 对于多线程(并发)和Spring Boot这两块在同步进行学习中,在看到使用synchronized关键字使操作同步时,看到和C#中不一样的东西,所以这里呢,就深入学习了下,若有错误之处,还望指 ...
- synchronized 线程同步-类级别锁定
1.demo 说明:代码中通过 printNum 方法传入参数判断 a.b 分别对 num 这个参数的值进行了修改. package demo1; import sun.applet.Main; pu ...
- jQuery插件开发全解析,类级别与对象级别开发
jQuery插件的开发包括两种: 一种是类级别的插件开发,即给jQuery添加新的全局函数,相当于给jQuery类本身添加方法.jQuery的全局函数就是属于jQuery命名空间的函数,另一种是对象级 ...
随机推荐
- Codeforces Round #712 (Div. 2)
A. Déjà Vu 题意:就是问能否加上字母a,使得字符串不中心对称 思路:只有一种情况不能加入,就是全部是a,剩下的都可以满足,找a的位置就找哪个字母不是a,然后让它的对称位置是新加的这个a 代码 ...
- (转)通过gitlab统计git提交的代码量
git的代码量大多数都是根据命令行统计,或者根据第三方插件统计.但是都不满足我的需求,因为我们代码都由gitlab管理,于是想到了通过gitlab暴露出来的接口获取数据. 第一步,生成私钥 登录你的g ...
- CRM系统实现自动化的“三部曲”
在了解CRM系统的自动化的时候,我们先来看一下CRM能干什么. 从上面的流程图我们就可以看出,CRM可以管理售前,售中和售后的整个客户生命周期. 为什么在复杂的客户生命周期中需要自动化呢? 当然是为了 ...
- 普里姆算法(Prim)
概览 普里姆算法(Prim算法),图论中的一种算法,可在加权连通图(带权图)里搜索最小生成树.即此算法搜索到的边(Edge)子集所构成的树中,不但包括了连通图里的所有顶点(Vertex)且其所有边的权 ...
- [c++] 内存与变量
内存 程序代码区用来保存指令,常量区.全局数据区.堆.栈都用来保存数据 常量区和全局数据区有时也被合称为静态数据区,意思是这段内存专门用来保存数据,在程序运行期间一直存在 函数被调用时,会将参数.局部 ...
- [文章]Linux宕机故障分析案例
[文章]Linux宕机故障分析案例 已采纳 收藏 0 1669 0 马化辉 2018-07-01发布 背景 在Linux系统环境下,服务器宕机发生的频率比较小,但是不少工程师或多或少都会遇到这 ...
- Job for ssh.service failed because the control process exited with error code. See "systemctl status ssh.service" and "journalctl -xe" for details.
1.按照提示 systemctl status ssh.service 查看报错原因 sshd -t 2.结果 /etc/ssh/sshd_config line 34: missing argume ...
- mitogen附带文件到远程主机
#!/usr/bin/env python # import mitogen.master import mitogen.select import subprocess import logging ...
- Windows(受控主机)上配置
Powershell版本要求及配置 windows需要使用Powershell4.0及以上版本,入下图所示,如果不是4.0及以上的需要升级 一.升级Powershell至3.0+ 1. 下载并安装Mi ...
- /var/log/syslog日志usb接口
p:~# cat /proc/bus/input/devices |grep usbP: Phys=usb-0000:00:05.1-1/buttonS: Sysfs=/devices/pci0000 ...