Java synchronized 关键字详解

前置技能点

  • 进程和线程的概念
  • 线程创建方式
  • 线程的状态状态转换
  • 线程安全的概念

synchronized 关键字的几种用法

  1. 修饰非静态成员方法

    synchronized public void sync(){
    
    }
  2. 修饰静态成员方法

    synchronized public static void sync(){
    
    }
  3. 类锁代码块

    synchronized (类.class){
    
    }
  4. 对象锁代码块

    synchronized (this|对象){
    
    }

synchronized 修饰非静态方法时可以看做是锁 this 对象,修饰静态方法时可以看做是锁方法所在的类。

synchronized 关键字的根本机制

各个线程想要访问被 synchronized 修饰的代码块,就要取得 synchronized 声明的锁。如果两个线程的目标是同一个锁,就会出现阻塞的现象,所以两个线程不能同时访问同一个锁下的代码,保证了多线程在执行时最终结果不会出错。这与共享变量是否为静态无关。

几个例子

对象锁

public class ThreadDemo extends Thread {
@Override
public synchronized void run() {
for (int i = 0; i < 10000; i++) {
Main.i++;
}
System.out.println("执行完成");
}
}

直接将继承的 run() 方法标记为 synchronized ,作用是对 Main 类中的 i 变量做 10000 次累加操作。

public class Main {
static int i = 0; public static void main(String[] args) throws InterruptedException {
ThreadDemo threadDemo=new ThreadDemo();
Thread t1 = new Thread(threadDemo);
Thread t2 = new Thread(threadDemo);
Thread t3 = new Thread(threadDemo);
Thread t4 = new Thread(threadDemo); t1.start();
t2.start();
t3.start();
t4.start(); t1.join();
t2.join();
t3.join();
t4.join();
System.out.println(i);
}
}
//输出结果:
//执行完成
//执行完成
//执行完成
//执行完成
//40000

可以看到当4个线程全部执行完毕之后,变量 i 成功的累加了 40000 次,没有出现丢失操作的情况。

如果我们将 main() 方法修改如下:

public static void main(String[] args) throws InterruptedException {
Thread t1 = new ThreadDemo();
Thread t2 = new ThreadDemo();
Thread t3 = new ThreadDemo();
Thread t4 = new ThreadDemo(); t1.start();
t2.start();
t3.start();
t4.start(); t1.join();
t2.join();
t3.join();
t4.join();
System.out.println(i);
}
//输出结果:
//执行完成
//执行完成
//执行完成
//执行完成
//27579

可以看到丢失了不少的累加操作。观察前后两个 main() 方法创建线程的方式可以发现,前面的 main() 方法是使用了同一个对象来创建了4个不同的线程,而后一个 main() 方法使用了4个不同的 ThreadDemo 对象创建了4个线程。我们用 synchronized 修饰的是一个非静态成员函数,相当于对该方法创建了 this 的对象锁。在第一个 main() 方法中使用同一个对象来创建 4 个不同线程就会让 4 个线程争夺同一个对象锁,这样,在同一时间内,仅能有一个线程能访问 synchronized 修饰的方法。而在第二种 main() 方法中,4 个线程各自对应一个对象锁,4 个线程之间没有竞争关系,对象锁自然无法生效。

类锁

public class ThreadDemo extends Thread {
@Override
public void run() {
synchronized (ThreadDemo.class) {
for (int i = 0; i < 10000; i++) {
Main.i++;
}
System.out.println("执行完成");
}
}
}

将修饰方法的 synchronized 改为对 ThreadDemo.class 上锁的代码块

public class ThreadDemo2 extends Thread {
@Override
public void run() {
synchronized (ThreadDemo2.class) {
for (int i = 0; i < 10000; i++) {
Main.i++;
}
System.out.println("执行完成");
}
}
}

再创建一个相同的类命名为 ThreadDemo2 ,与 ThreadDemo 不同的是,ThreadDemo2 中,synchronized 对 ThreadDemo2.class 上锁。

public static void main(String[] args) throws InterruptedException {
Thread t1 = new ThreadDemo();
Thread t2 = new ThreadDemo();
Thread t3 = new ThreadDemo2();
Thread t4 = new ThreadDemo2(); t1.start();
t2.start();
t3.start();
t4.start(); t1.join();
t2.join();
t3.join();
t4.join();
System.out.println(i);
}
//输出结果:
//执行完成
//执行完成
//执行完成
//执行完成
//33054

4 个线程分别由 ThreadDemo 和 ThreadDemo2 来创建,显然得到的结果与预期的 40000 不符。如果我们将 ThreadDemo2 中的 synchronized 改为对 ThreadDemo.class 上锁:

public class ThreadDemo2 extends Thread {
@Override
public void run() {
synchronized (ThreadDemo.class) {
for (int i = 0; i < 10000; i++) {
Main.i++;
}
System.out.println("执行完成");
}
}
}
//输出结果:
//执行完成
//执行完成
//执行完成
//执行完成
//40000

可以看到,虽然是声明在两个不同的类中的 synchronized 代码块,但是由于都是对 ThreadDemo.class 上锁,所以 4 个线程之间还是建立了竞争关系,同时只能有一个线程访问被 synchronized 修饰的代码。

总结

所以 synchronized 关键字的本质是限制线程访问一段代码,而限制的条件就是,在所有被加上相同锁的代码上,同一时间,只能有一个线程在运行。这与你要修改什么样的共享变量无关。在我刚接触到的时候以为类锁和对象锁是分别针对静态共享变量和非静态共享变量的,但事实上锁的是要执行的代码块,而不是代码块将要访问的共享变量。

Java synchronized 关键字详解的更多相关文章

  1. [java] java synchronized 关键字详解

    Java语言的关键字,可用来给对象和方法或者代码块加锁,当它锁定一个方法或者一个代码块的时候,同一时刻最多只有一个线程执行这段代码.当两个并发线程访问同一个对象object中的这个加锁同步代码块时,一 ...

  2. Java多线程(三)—— synchronized关键字详解

    一.多线程的同步 1.为什么要引入同步机制 在多线程环境中,可能会有两个甚至更多的线程试图同时访问一个有限的资源.必须对这种潜在资源冲突进行预防. 解决方法:在线程使用一个资源时为其加锁即可. 访问资 ...

  3. “全栈2019”Java多线程第十六章:同步synchronized关键字详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  4. Java volatile关键字详解

    Java volatile关键字详解 volatile是java中的一个关键字,用于修饰变量.被此关键修饰的变量可以禁止对此变量操作的指令进行重排,还有保持内存的可见性. 简言之它的作用就是: 禁止指 ...

  5. Java 多线程(六) synchronized关键字详解

    多线程的同步机制对资源进行加锁,使得在同一个时间,只有一个线程可以进行操作,同步用以解决多个线程同时访问时可能出现的问题. 同步机制可以使用synchronized关键字实现. 当synchroniz ...

  6. 从线程池到synchronized关键字详解

    线程池 BlockingQueue synchronized volatile 前段时间看了一篇关于"一名3年工作经验的程序员应该具备的技能"文章,倍受打击.很多熟悉而又陌生的知识 ...

  7. java synchronized 同步详解

    记下来,很重要. Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码. 一.当两个并发线程访问同一个对象object中的这个synchron ...

  8. 简单的互斥同步方式——synchronized关键字详解

    目录 1. 关于synchronized关键字 2. synchronized的原理和实现细节 2.1 synchronized可以用在那些地方 2.2 synchronized是如何实现线程互斥访问 ...

  9. synchronized关键字详解(二)

    synchronized关键字的性质 1.可重入:同一线程的外层函数获得锁之后,内层函数可直接再次获得该锁,好处:避免死锁,提升封装性 证明可重入粒度:1.同一个方法是可重入的 2.可重入不要求是同一 ...

随机推荐

  1. 创建django报错使用miniconda

    sqlite文件缺失 下载地址 https://sqlite.org/download.html https://blog.csdn.net/xuzhexing/article/details/905 ...

  2. typedef声明变量也是一种求值过程

    前言: 什么叫做:声明变量是求值过程?请看下面的声明, int i; 很简单,声明了个整型变量i,再看如下声明, int *p; 也很简单,立刻反应出来它是指向整型的指针,但是具体如何推倒出来的呢?其 ...

  3. mybatis增强工具MyBatis-plus

    如果你正在用mybatis,那MyBatis-plus你不能错过,配合使用可极大简化开发.提高效率! 简介 MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis ...

  4. 团队作业-Alpha版本发布2

    团队项目-系统设计 这个作业属于哪个课程 https://edu.cnblogs.com/campus/xnsy/GeographicInformationScience/homework 这个作业要 ...

  5. JSP-导入taglib 出现classNotFound异常

    案例 前端登录跳转到指定jsp,报classNoFoundException,原因是页面导入 <%@ taglib uri="http://java.sun.com/jsp/jstl/ ...

  6. Linux防火墙之iptables基本匹配条件和隐式扩展匹配条件

    一.iptables的基本匹配条件 上一篇博文我们说到了iptables的基本工作原理.数据报文在内核的走向和管理链.管理规则.以及查看规则.导入和导出规则:回顾请参考https://www.cnbl ...

  7. Word文档分节设置页码

    在一篇论文中需要将摘要和目录作为一部分设置罗马数字页码,正文部分设置阿拉伯数字页码. 大致效果如下图所示: 这里面用到了分节符,步骤如下: 1 :点击开始菜单栏下 显示/隐藏编辑标记 2:点击插入菜单 ...

  8. gulp的简单打包示例(一)

    引言 前端开发,打包工具是必不可少的,虽然有很多别人帮你封装好的打包工具,但自己配置一个,自身的实力也会大增呀.这篇博文主要讲的是使用gulp对html.js.less.css.图片的压缩合并等配置. ...

  9. k8s-dashboard的部署与卸载

    相对于枯燥的命令行管理,控制台的管理方式相对就显得更加直观便捷了,虽然官方的dashboard有点不太好用,但是作为免费的dashaboard还是可以体验一番的,下面开始部署这个难用的dashboar ...

  10. VS Code 1.42 发布!2020 年首个大更新

    近日(北京时间 2020 年 2 月 7 日),微软发布了 Visual Studio Code 1.42 版本,这也是 2020 年 VS Code 首次大更新.让我们来看看有哪些主要的更新. 支持 ...