前言

相信不少同学在上完Java课后,对于线程同步部分的实战,都会感到不知其然。

比如上课做实验的时候,按着老师的实验指导书中的描述完成了多线程的同步操作,就感觉自己已经掌握这个知识点了,实际运用中再次手足无措,就像我一样。 这里提问一下:synchronized对方法修饰,在别处调用这个方法时,谁被锁定了呢?另外,在新建线程中使用synchronized(this){ }结构时,如:

void methodA() {
new Thread(() -> {
synchronized (this) {
this.methodB();
}
}).start();
}

这个被锁的this又是谁呢?

这篇博文来详细介绍一下线程同步中涉及synchronized修饰的两种用法:同步方法和同步代码块。

才不会说这篇是我对一个项目代码中的线程同步机制感到迷惑而搜资料写的笔记(

同步方法

先开始介绍synchronized修饰符本身的特性:

  1. synchronized关键字不能被继承 即父类方法是同步方法 子类方法继承后默认不是同步方法
  2. synchronized不能修饰接口方法 因为接口是特殊的抽象类 不能新建实例 实例锁应归实现其的类所有
  3. synchronized不能修饰构造方法(但可在内部使用synchronized代码块来同步

类的成员方法

修饰一个普通方法时,作用域是当前调用对象,即只要还没出方法的作用域,其他试图获取该对象的锁线程都将被阻塞。

这里容易误解的就是,只是尝试获取该对象锁的线程会被阻塞,并不影响其他线程不获取锁瞎操作,所以要在涉及同步量操作的所有地方采用同步方法(如加锁),否则引起线程安全问题几乎是必然的。

类的静态方法

因为类的静态方法属于类,而不属于类的某个特定实例,所以对类的静态方法修饰直接作用于类本身,相当于synchronized(ClassA.class),即直接锁定整个类。这里有不少别人的笔记写着,直接作用于类的所有对象,我觉得存在歧义,因为正常情况下,除非采用工厂模式之类的方法,不然很难获取到所有对象的引用,并且这种表述也是不符合直觉的。

同步代码块

由于同步是一个高开销操作,上面讲的同步方法其实是同步代码块的一个语法糖,平时应尽量使用synchronized同步关键代码,而不是对整个方法同步,要尽可能减少同步的内容。

对成员方法修饰 -> synchronized(this)

对静态方法修饰 -> synchronized(ClassA.class)

总结

自己全部测试了一遍,重新验证了猜想,目测没有什么不符合直觉的地方,另外,对单独信号量,如byte[]之类的加锁操作,如果不释放锁,其他线程会全部阻塞在获取锁的过程中,这里不单列出来。

本文前言中提到的问题,答案即为新建这个线程的实例本身,而不是这个被新建的线程类。

这里看到结果就容易理解了,每个对象都自己与一个锁相关联,类静态本身也与一个锁关联,任何尝试获取锁的方法才可能会引起阻塞。

修饰对象/其他线程 同实例 其他实例
阻塞/不阻塞 成员变量 非同步方法 同步方法 成员变量 非同步方法 同步方法 静态变量 静态非同步方法 静态同步方法
this 不阻塞 不阻塞 阻塞 不阻塞 不阻塞 不阻塞
类的成员方法 不阻塞 不阻塞 阻塞 不阻塞
类.class - 阻塞
类的静态方法 阻塞

其他同步方法

这里就不多介绍了,下面遇到了再详细写。

  1. 使用volatile修饰域 每次使用此域都需重新计算
  2. 使用ReentrantLock可重入锁 需要注意及时手动释放 通常在finally里释放
  3. 使用ThreadLocal 这里反对本文参考资料中的一个介绍 严格来说这不叫同步 只是各个使用到相同类的线程 独立的创建一份自己的副本 由于这个副本仅当前线程可达 也就没有了其他线程的竞争 相当于线程内部的全局变量 应用场景主要有两种 一是单个线程中多个类的实例共享另一个实例的时候 如数据库连接、RequestContextHolder、Web Session、日志的MDC、SimpleDateFormat(线程不安全的工具类)等 二是避免超长参数传递链 避免在方法中来回传递参数
  4. 使用LinkedBlockingQueue阻塞队列 利用队列FIFO(先进先出)的特性实现生产者-消费者模型
  5. 使用Atomic原子变量 利用原子操作本身的特性实现多线程同步

参考资料

java-synchronized-method-lock-on-object-or-method - stackoverflow

what-is-the-reason-why-synchronized-is-not-allowed-in-java-8-interface-methods - stackoverflow

Java线程同步的7种方式 - cnblogs

关于Java的构造方法在类初始化和类实例化中的实质 - CSDN

Java中Synchronized的用法 - CSDN

Java多线程安全之构造函数 - CSDN

正确理解Thread Local的原理与适用场景 - 个人博客

理解Java中的ThreadLocal - 个人博客

Java中的四种引用类型(强、软、弱、虚) - 简书

Java同步方法:synchronized到底锁住了谁?的更多相关文章

  1. synchronized到底锁住的是谁?

    本文代码仓库:https://github.com/yu-linfeng/BlogRepositories/tree/master/repositories/sync 先来一道校招级并发编程笔试题 题 ...

  2. Java synchronized到底锁住的是什么?

    使用环境:多线程java程序中. 作用:在多线程的环境下,控制synchronized代码段不被多个线程同时执行.synchronized既可以加在一段代码上,也可以加在方法上. 使用:synchro ...

  3. java synchronized究竟锁住的是什么

    刚学java的时候,仅仅知道synchronized一个线程锁.能够锁住代码,可是它真的能像我想的那样,能够锁住代码吗? 在讨论之前先看一下项目中常见关于synchronized的使用方法: publ ...

  4. Java synchronized(this)锁住的是什么

    synchronized锁住的是括号里面的对象,而不是代码. 对于非static的synchronized方法,锁的就是对象本身,也就是this.

  5. 关于synchronized无法锁住Integer原因

    原因 在多线程的时候,为了保证数据安全,必须在修改数据时使用线程同步,java中的synchronized用来实现线程同步.线程列队. 学完多线程基础的我,写一个多线程交替输出1,2,3,4,5... ...

  6. 关于Synchronized关键字锁住对象的嵌套问题

    如果在子关键字代码块中调用了sleep,是否会保留有所的锁?

  7. Java并发,synchronized锁住的内容

    synchronized用在方法上锁住的是什么? 锁住的是当前对象的当前方法,会使得其他线程访问该对象的synchronized方法或者代码块阻塞,但并不会阻塞非synchronized方法. 脏读 ...

  8. 由Java 15废弃偏向锁,谈谈Java Synchronized 的锁机制

    Java 15 废弃偏向锁 JDK 15已经在2020年9月15日发布,详情见 JDK 15 官方计划.其中有一项更新是废弃偏向锁,官方的详细说明在:JEP 374: Disable and Depr ...

  9. 从分布式锁角度理解Java的synchronized关键字

    分布式锁 分布式锁就以zookeeper为例,zookeeper是一个分布式系统的协调器,我们将其理解为一个文件系统,可以在zookeeper服务器中创建或删除文件夹或文件.设D为一个数据系统,不具备 ...

随机推荐

  1. Dubbo与Spring Cloud的比较

    区别: ----- 来源(背景): Dubbo,是阿里巴巴服务化治理的核心框架,并被广泛应用于阿里巴巴集团的各成员站点. Spring Cloud,从命名我们就可以知道,它是Spring Source ...

  2. java模拟栈的操作

    栈是一种有序列表,可以使用数组的结构来储存栈的数据内容 思路 1. 创建一个栈类StackArray 2. 定义一个top来模拟栈顶,初始化为-1 3. 入栈: 当有数据加入到栈的时候 top++ s ...

  3. vue 听说你很会传值?

    前置 大小 vue 项目都离不开组件通讯, 在这里总结一下vue组件通讯方式并列出, 都是简单的例子. 适合像我这样的小白.如有错误,欢迎指正. 温馨提示: 下文没有列出 vuex, vuex 也是重 ...

  4. 使用 nodejs 对文件进行批量重命名

    0. 前言 从B站下载了一点视频,硕鼠自动将标题添加到了每个文件名的前面,导致文件名过长,不方面查看文件的具体内容. 虽然只有二十几个文件,但是手动删除前缀还是个不小的工作量,还有可能删除错误.考虑到 ...

  5. 实验十三 MySQL多用户事务管理

    实验十三 MySQL多用户事务管理 一.  实验内容: 1. 事务机制的使用 2. 锁机制的使用 二.  实验项目:员工管理数据库 用于企业管理的员工管理数据库,数据库名为YGGL中,YGGL数据库中 ...

  6. Gin框架04:趣谈参数绑定与校验

    导读 在第二节,我们学习了Gin框架的路由定义与参数接收,今天应一位同学的要求,来讲解一下参数的绑定与校验. 为什么校验参数? 本不必抛出这个问题的,但顾及到初出茅庐的同学,这里解释一下. 假设做一个 ...

  7. 1008 Elevator (20 分)

    The highest building in our city has only one elevator. A request list is made up with N positive nu ...

  8. linux下shell脚本中sed命令的用法

    先来给一个案例: #将old.sql文件中的符号“|”替换为“,”,并保存到test.sql文件中 sed "s/|/,/g" "old.sql"> te ...

  9. 【Linux】网络应用

    一. 网络基本配置 setup 永久网络设置 (IP 网关 DNS) vim /etc/sysconfig/network-scripts/ifcfg-eth0 (网卡信息文件) route -n 查 ...

  10. django自定义404和500页面

    from django.contrib import admin from django.urls import path urlpatterns = [ path('admin/', admin.s ...