前言

在Java中,有一个常被忽略 但 非常重要的关键字Synchronized

今天,我将详细讲解 Java关键字Synchronized的所有知识,希望你们会喜欢

目录

示意图

1. 定义

Java中的1个关键字

2. 作用

保证同一时刻最多只有1个线程执行 被Synchronized修饰的方法 / 代码

其他线程 必须等待当前线程执行完该方法 / 代码块后才能执行该方法 / 代码块

3. 应用场景

保证线程安全,解决多线程中的并发同步问题(实现的是阻塞型并发),具体场景如下:

修饰 实例方法 / 代码块时,(同步)保护的是同一个对象方法的调用 & 当前实例对象

修饰 静态方法 / 代码块时,(同步)保护的是 静态方法的调用 & class 类对象

4. 原理

依赖 JVM 实现同步

底层通过一个监视器对象(monitor)完成, wait()、notify() 等方法也依赖于 monitor 对象

监视器锁(monitor)的本质 依赖于 底层操作系统的互斥锁(Mutex Lock)实现

5. 具体使用

Synchronized 用于 修饰 代码块、类的实例方法 & 静态方法

5.1 使用规则

示意图

5.2 锁的类型 & 等级

由于Synchronized 会修饰 代码块、类的实例方法 & 静态方法,故分为不同锁的类型

具体如下

示意图

之间的区别

示意图

5.3 使用方式

/**

* 对象锁

*/

public class Test{

// 对象锁:形式1(方法锁)

public synchronized void Method1(){

System.out.println("我是对象锁也是方法锁");

try{

Thread.sleep(500);

} catch (InterruptedException e){

e.printStackTrace();

}

}

// 对象锁:形式2(代码块形式)

public void Method2(){

synchronized (this){

System.out.println("我是对象锁");

try{

Thread.sleep(500);

} catch (InterruptedException e){

e.printStackTrace();

}

}

}

/**

* 方法锁(即对象锁中的形式1)

*/

public synchronized void Method1(){

System.out.println("我是对象锁也是方法锁");

try{

Thread.sleep(500);

} catch (InterruptedException e){

e.printStackTrace();

}

}

/**

* 类锁

*/

public class Test{

// 类锁:形式1 :锁静态方法

public static synchronized void Method1(){

System.out.println("我是类锁一号");

try{

Thread.sleep(500);

} catch (InterruptedException e){

e.printStackTrace();

}

}

// 类锁:形式2 :锁静态代码块

public void Method2(){

synchronized (Test.class){

System.out.println("我是类锁二号");

try{

Thread.sleep(500);

} catch (InterruptedException e){

e.printStackTrace();

}

}

}

5.4 特别注意

Synchronized修饰方法时存在缺陷:若修饰1个大的方法,将会大大影响效率

示例

若使用Synchronized关键字修饰 线程类的run(),由于run()在线程的整个生命期内一直在运行,因此将导致它对本类任何Synchronized方法的调用都永远不会成功

解决方案

使用 Synchronized关键字声明代码块

该解决方案灵活性高:可针对任意代码块 & 任意指定上锁的对象

代码如下

synchronized(syncObject) {

// 访问或修改被锁保护的共享状态

// 上述方法 必须 获得对象 syncObject(类实例或类)的锁

}

6. 特点

示意图

注:原子性、可见性、有序性的定义

示意图

7. 其他控制并发 / 线程同步方式

7.1 Lock、ReentrantLock

简介

示意图

区别

示意图

7.2 CAS

7.2.1 定义

Compare And Swap,即 比较 并 交换,是一种解决并发操作的乐观锁

synchronized锁住的代码块:同一时刻只能由一个线程访问,属于悲观锁

7.2.2 原理

// CAS的操作参数

内存位置(A)

预期原值(B)

预期新值(C)

// 使用CAS解决并发的原理:

// 1. 首先比较A、B,若相等,则更新A中的值为C、返回True;若不相等,则返回false;

// 2. 通过死循环,以不断尝试尝试更新的方式实现并发

// 伪代码如下

public boolean compareAndSwap(long memoryA, int oldB, int newC){

if(memoryA.get() == oldB){

memoryA.set(newC);

return true;

}

return false;

}

7.2.3 优点

资源耗费少:相对于synchronized,省去了挂起线程、恢复线程的开销

但,若迟迟得不到更新,死循环对CPU资源也是一种浪费

7.2.4 具体实现方式

使用CAS有个“先检查后执行”的操作

而这种操作在Java中是典型的不安全的操作,所以 CAS在实际中是由C++通过调用CPU指令实现的

具体过程

// 1. CAS在Java中的体现为Unsafe类

// 2. Unsafe类会通过C++直接获取到属性的内存地址

// 3. 接下来CAS由C++的Atomic::cmpxchg系列方法实现

7.2.5 典型应用:AtomicInteger

对 i++ 与 i--,通过compareAndSet & 一个死循环实现

而compareAndSet函数内部 = 通过jni操作CAS指令。直到CAS操作成功跳出循环

private volatile int value;

/**

* Gets the current value.

*

* @return the current value

*/

public final int get() {

return value;

}

/**

* Atomically increments by one the current value.

*

* @return the previous value

*/

public final int getAndIncrement() {

for (;;) {

int current = get();

int next = current + 1;

if (compareAndSet(current, next))

return current;

}

}

/**

* Atomically decrements by one the current value.

*

* @return the previous value

*/

public final int getAndDecrement() {

for (;;) {

int current = get();

int next = current - 1;

if (compareAndSet(current, next))

return current;

}

}

8. 总结

本文主要对Java中常被忽略 但 非常重要的关键字Synchronized进行讲解

下面我将继续对 Android & Java中的知识进行深入讲解 ,感兴趣的同学可以继续关注本人运营的Wechat Public Account:

请点赞!因为你的鼓励是我写作的最大动力!

不定期分享关于安卓开发的干货,追求短、平、快,但却不缺深度。

java synchronized关键字_Java:手把手教你全面学习神秘的Synchronized关键字相关推荐

  1. java标识语_Java 基本语法,标识符,修饰符,关键字

    基本语法 在编写Java代码时,需要特别注意几个关键: 两种语句:Java 中的程序代码可分为结构定义语句和功能执行语句,其中结构定义语句用于声明一个类或方法,功能执行语句用于实现具体的功能.每条功能 ...

  2. java编写爬虫_手把手教你从零开始用Java写爬虫

    本文将手把手地教大家从零开始用Java写一个简单地爬虫! 目标 爬取全景网图片,并下载到本地 收获 通过本文,你将复习到:IDEA创建工程 IDEA导入jar包 爬虫的基本原理 Jsoup的基本使用 ...

  3. django调用java_07.手把手教将深度学习利用Django将模型发布成服务供java调用

    标题 问题 一.python发布成服务 1.先建立一个深度学习模型并训练好 2.建立一个预测方法去调用训练好的模型 3.建立一个Django工程 4.将python利用模型预测的代码放入Django项 ...

  4. 手把手教安装java开发环境_手把手教你配置java开发环境-java环境变量设置

    在本篇中将为大家介绍如何在windows下搭建Java的开发环境. 话不多说,直接转入正题.下载java开发工具包JDK 下载地址:http://www.oracle.com/technetwork/ ...

  5. java解析多层json,手把手教你怎么解析多层嵌套的JSON数据(使用JSONModel)

    2018.11.14日更新 前言 没想到这篇简单介绍JSONModel的文章竟然已经破了两千阅读量,一跃成为我阅读量最高的文章,作为iOS小白的我感到万分惶恐 在这一个月的项目中,总是用到JSONMo ...

  6. 超详细Java基础小项目-手把手教你制作万年历~~~自己动手试一下吧!

    任务需求 完成从控制台输入XXXX年XX月,输出该月日历. 运行效果如下图所示: 项目分析: 最难的部分就是星期的确定,已知 1900 年 1 月 1 日为星期一,计算出当前月份的 1 号距离1900 ...

  7. 【java家教系统】手把手教你制作计算机毕业设计(附源码+课件)

    很多大四同学苦于没有参考的毕设资料,或者下载的资料不全.代码有问题,数据有问题等等,造成毕设出现问题影响大学毕业.现在,免费提供项目源码和视频教程,让大家在短时间内可以完成自己的毕业设计. 对于jav ...

  8. java 读取带section_手把手教你实现类似ini4j的方式创建读取和修改.ini文件(支持section)...

    背景 由于这次任务是和c语言合作编写的,刚开始使用ini4j来操作.ini文件,然后由于ini4j对存储的数据做了转义处理,导致c无法正常读取,他们也是采用开源的框架,然后由于java方只有我一个人, ...

  9. 大牛手把手教你!一起来聊聊Synchronized底层实现原理

    前言 Java作为最全面的语言,国内开发者也是最多的,Java综合起来各方面都不错,在大部分场景下是一种稳健的技术选择.加上近年来安卓的推动,目前也是最流行的一种语言. 现在Java的就业市场看起来还 ...

最新文章

  1. Python使用shape计算矩阵的行和列
  2. 《Spark大数据分析:核心概念、技术及实践》大数据技术一览
  3. web3.js(一)根据地址查询以太数量
  4. java在主程序修改函数输出,Java通过JNI调用CUDA
  5. [_CN] Eclipse精要与高级开发技术 note
  6. 全国计算机等级考试题库二级C操作题100套(第91套)
  7. FlexViewer2.3中拉帘Widget下载
  8. 使用Dockerfile构建自己的etcd镜像
  9. JDK5.0新特性系列---11.5.4线程 同步装置之Exchanger
  10. [kuangbin带你飞] 专题一简单搜索
  11. Word 2010基本操作——新建文档、保存文档
  12. autolayout教程Android,AndroidAutoLayout的简单阅读
  13. shell 数组及 十六进制转换报错
  14. Java操作Oracle数据库——ARRAY TABLE类型批量数据处理区别比较
  15. Spring Cloud与Dubbo怎么选择?
  16. pandas系列学习(七):数据透视表
  17. 【csdn学习-Python】CSDN技能树-Python语言学习笔记
  18. net中winform教程 浏览器控件,还是微软的WebView2最好用
  19. ipa上架App Store流程
  20. html文件只能打印一页,javascript – 使用window.print()打印巨大的表只打印一页

热门文章

  1. WPFWCFWF打造HelloWorld程序
  2. PendingIntent与Intent区别
  3. js 两行之间的设置间距_厂房仓库的防火间距考点汇总
  4. float32精度_混合精度对模型训练和推理的影响
  5. 【MM模块】Batch 批次管理 2
  6. 【PP生产订单】入门介绍(十二)
  7. 关于通过使用BAPI创建销售订单(抬头信息中:含增强字段)
  8. 用通俗易懂的大白话讲解Map/Reduce原理
  9. 针对当前项目SLED存在短缺XX天
  10. 采购申请的评估价格的来源