文章目录

  • 为什么要同步
  • Synchronized关键词
    • Synchronized Instance Methods
    • Synchronized Static Methods
    • Synchronized Blocks

java并发中的Synchronized关键词

如果在多线程的环境中,我们经常会遇到资源竞争的情况,比如多个线程要去同时修改同一个共享变量,这时候,就需要对资源的访问方法进行一定的处理,保证同一时间只有一个线程访问。

java提供了synchronized关键字,方便我们实现上述操作。

为什么要同步

我们举个例子,我们创建一个类,提供了一个setSum的方法:


public class SynchronizedMethods {private int sum = 0;public void calculate() {setSum(getSum() + 1);}
}

如果我们在多线程的环境中调用这个calculate方法:

    @Testpublic void givenMultiThread_whenNonSyncMethod() throws InterruptedException {ExecutorService service = Executors.newFixedThreadPool(3);SynchronizedMethods summation = new SynchronizedMethods();IntStream.range(0, 1000).forEach(count -> service.submit(summation::calculate));service.shutdown();service.awaitTermination(1000, TimeUnit.MILLISECONDS);assertEquals(1000, summation.getSum());}

按照上面的方法,我们预计要返回1000, 但是实际上基本不可能得到1000这个值,因为在多线程环境中,对同一个资源进行同时操作带来的不利影响。

那我们怎么才能够建线程安全的环境呢?

Synchronized关键词

java提供了多种线程安全的方法,本文主要讲解Synchronized关键词,Synchronized关键词可以有很多种形式:

  • Instance methods
  • Static methods
  • Code blocks

当我们使用synchronized时,java会在相应的对象上加锁,从而在同一个对象等待锁的方法都必须顺序执行,从而保证了线程的安全。

Synchronized Instance Methods

Synchronized关键词可以放在实例方法的前面:

    public synchronized void synchronisedCalculate() {setSum(getSum() + 1);}

看下调用结果:

@Test
public void givenMultiThread_whenMethodSync() {ExecutorService service = Executors.newFixedThreadPool(3);SynchronizedMethods method = new SynchronizedMethods();IntStream.range(0, 1000).forEach(count -> service.submit(method::synchronisedCalculate));service.awaitTermination(1000, TimeUnit.MILLISECONDS);assertEquals(1000, method.getSum());
}

这里synchronized将会锁住该方法的实例对象,多个线程中只有获得该实例对象锁的线程才能够执行。

Synchronized Static Methods

Synchronized关键词也可以用在static方法前面:

    public static synchronized void syncStaticCalculate() {staticSum = staticSum + 1;}

Synchronized放在static方法前面和实例方法前面锁住的对象不同。放在static方法前面锁住的对象是这个Class本身,因为一个Class在JVM中只会存在一个,所以不管有多少该Class的实例,在同一时刻只会有一个线程可以执行该放方法。

    @Testpublic void givenMultiThread_whenStaticSyncMethod() throws InterruptedException {ExecutorService service = Executors.newCachedThreadPool();IntStream.range(0, 1000).forEach(count ->service.submit(SynchronizedMethods::syncStaticCalculate));service.shutdown();service.awaitTermination(100, TimeUnit.MILLISECONDS);assertEquals(1000, SynchronizedMethods.staticSum);}

Synchronized Blocks

有时候,我们可能不需要Synchronize整个方法,而是同步其中的一部分,这时候,我们可以使用Synchronized Blocks:

    public void performSynchronizedTask() {synchronized (this) {setSum(getSum() + 1);}}

我们看下怎么测试:

    @Testpublic void givenMultiThread_whenBlockSync() throws InterruptedException {ExecutorService service = Executors.newFixedThreadPool(3);SynchronizedMethods synchronizedBlocks = new SynchronizedMethods();IntStream.range(0, 1000).forEach(count ->service.submit(synchronizedBlocks::performSynchronizedTask));service.shutdown();service.awaitTermination(100, TimeUnit.MILLISECONDS);assertEquals(1000, synchronizedBlocks.getSum());}

上面我们同步的是实例,如果在静态方法中,我们也可以同步class:

    public static void performStaticSyncTask(){synchronized (SynchronizedMethods.class) {staticSum = staticSum + 1;}}

我们看下怎么测试:

    @Testpublic void givenMultiThread_whenStaticSyncBlock() throws InterruptedException {ExecutorService service = Executors.newCachedThreadPool();IntStream.range(0, 1000).forEach(count ->service.submit(SynchronizedMethods::performStaticSyncTask));service.shutdown();service.awaitTermination(100, TimeUnit.MILLISECONDS);assertEquals(1000, SynchronizedMethods.staticSum);}

本文的例子可以参考https://github.com/ddean2009/learn-java-concurrency/tree/master/Synchronized

更多精彩内容且看:

  • 区块链从入门到放弃系列教程-涵盖密码学,超级账本,以太坊,Libra,比特币等持续更新
  • Spring Boot 2.X系列教程:七天从无到有掌握Spring Boot-持续更新
  • Spring 5.X系列教程:满足你对Spring5的一切想象-持续更新
  • java程序员从小工到专家成神之路(2020版)-持续更新中,附详细文章教程

更多内存可以参考http://www.flydean.com/java-concurrent-synchronized/

java并发中的Synchronized关键词相关推荐

  1. java并发中CountDownLatch的使用

    文章目录 主线程等待子线程全都结束之后再开始运行 等待所有线程都准备好再一起执行 停止CountdownLatch的await java并发中CountDownLatch的使用 在java并发中,控制 ...

  2. java并发中ExecutorService的使用

    文章目录 创建ExecutorService 为ExecutorService分配Tasks 关闭ExecutorService Future ScheduledExecutorService Exe ...

  3. HashMap在java并发中如何发生死循环

    转载自   HashMap在java并发中如何发生死循环 在多线程环境中,使用HashMap进行put操作时会引起死循环,导致CPU使用接近100%,下面通过代码分析一下为什么会发生死循环. 首先先分 ...

  4. 【死磕Java并发】—–深入分析synchronized的实现原理

    记得刚刚开始学习Java的时候,一遇到多线程情况就是synchronized,相对于当时的我们来说synchronized是这么的神奇而又强大,那个时候我们赋予它一个名字"同步", ...

  5. Java线程中关于Synchronized的用法

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

  6. Java并发编程之synchronized关键字解析

    前言 公司加班太狠了,都没啥时间充电,这周终于结束了.这次整理了Java并发编程里面的synchronized关键字,又称为隐式锁,与JUC包中的Lock显示锁相对应:这个关键字从Java诞生开始就有 ...

  7. Java 并发编程:Synchronized 及其实现原理

    作者:liuxiaopeng 原文链接: www.cnblogs.com/paddix/p/5367116.html 一.Synchronized的基本使用 Synchronized是Java中解决并 ...

  8. 死磕Java并发:深入分析synchronized的实现原理

    本文转载自公众号: Java技术驿站 记得刚刚开始学习Java的时候,一遇到多线程情况就是synchronized.对于当时的我们来说,synchronized是如此的神奇且强大.我们赋予它一个名字& ...

  9. 并发中的Synchronized、Lock、Volite、Map、ThreadLocal

    文章目录 Synchronized synchronized 的三种应用方式 synchronized 括号后面的对象 synchronized 的锁的原理 Java 对象头 synchronized ...

最新文章

  1. 在闲鱼传疯了,某大厂P8面试题库泄漏!
  2. 使用AppCompat项目模版
  3. Nodejs开源项目推荐
  4. vim 树形目录插件NERDTree安装及简单用法
  5. 关于mpvue音乐小程序github仓库设置私有的声明
  6. 原动力CMS PHP域名授权系统V3.0
  7. Kafka配置文件及解释
  8. uni-app 实现手写签名
  9. springboot中使用@Transactional注解事物不生效的原因
  10. 用matlab做谱分析程序,经典功率谱分析Matlab程序
  11. 指针详讲(一阶指针和二阶指针等指针各种用法详解)
  12. Cadence Allegro PCB绘制:布线后的操作教程
  13. 做产品和运营必须深参这5大人性弱点
  14. 【Linux 网络】IP校验和计算相关
  15. 几种常见的Shell:sh、bash、csh、tcsh、ash
  16. 成功的反义词不是失败,而是什么都不做
  17. 科普一下什么是企业邮箱,企业邮箱适合场景?
  18. 基于bitshares的身份认证系统设计思路
  19. 把Google图书嵌入到网站中
  20. 开关电源和LDO纹波

热门文章

  1. 数据分析与挖掘实战-家用电器用户行为分析与事件识别
  2. python绘图设置标题出现乱码_解决python2 绘图title,xlabel,ylabel出现中文乱码的问题...
  3. 【Boost】boost库中thread多线程详解4——谈谈recursive_mutex
  4. socket中的nagle算法
  5. Sql Server事务日志
  6. STL 之swap, iter_swap, swap_ranges
  7. C++的精髓——虚函数
  8. QUIC/HTTP2相关资料整理
  9. 数据结构与算法 | 插值查找
  10. 音视频技术开发周刊 | 183