java并发中的Synchronized关键词

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

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

为什么要同步

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


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

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

    @Test
public 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的实例,在同一时刻只会有一个线程可以执行该放方法。

    @Test
public 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);
}
}

我们看下怎么测试:

    @Test
public 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;
}
}

我们看下怎么测试:

    @Test
public 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

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

java并发中的Synchronized关键词的更多相关文章

  1. Java并发编程:synchronized

    Java并发编程:synchronized 虽然多线程编程极大地提高了效率,但是也会带来一定的隐患.比如说两个线程同时往一个数据库表中插入不重复的数据,就可能会导致数据库中插入了相同的数据.今天我们就 ...

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

    Java并发编程系列: Java 并发编程:核心理论 Java并发编程:Synchronized及其实现原理 Java并发编程:Synchronized底层优化(轻量级锁.偏向锁) Java 并发编程 ...

  3. Java并发编程:Synchronized底层优化(偏向锁、轻量级锁)

    Java并发编程系列: Java 并发编程:核心理论 Java并发编程:Synchronized及其实现原理 Java并发编程:Synchronized底层优化(轻量级锁.偏向锁) Java 并发编程 ...

  4. 【转】Java并发编程:synchronized

    一.什么时候会出现线程安全问题? 在单线程中不会出现线程安全问题,而在多线程编程中,有可能会出现同时访问同一个资源的情况,这种资源可以是各种类型的资源:一个变量.一个对象.一个文件.一个数据库表等,而 ...

  5. 4、Java并发编程:synchronized

    Java并发编程:synchronized 虽然多线程编程极大地提高了效率,但是也会带来一定的隐患.比如说两个线程同时往一个数据库表中插入不重复的数据,就可能会导致数据库中插入了相同的数据.今天我们就 ...

  6. 深入浅出Java并发中的CountDownLatch

      1. CountDownLatch 正如每个Java文档所描述的那样,CountDownLatch是一个同步工具类,它允许一个或多个线程一直等待,直到其他线程的操作执行完后再执行.在Java并发中 ...

  7. java并发中CountDownLatch的使用

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

  8. java并发中ExecutorService的使用

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

  9. java并发编程(2) --Synchronized与Volatile区别

    Synchronized 在多线程并发中synchronized一直是元老级别的角色.利用synchronized来实现同步具体有一下三种表现形式: 对于普通的同步方法,锁是当前实例对象. 对于静态同 ...

随机推荐

  1. Spring Boot 完整讲解

    SpringBoot学习笔记 文章写得比较详细,所以很长(105336 字数),可以参考目录 文章目录 SpringBoot学习笔记 @[toc] 一. Spring Boot 入门 预:必须掌握的技 ...

  2. linux系统部署安装过程

    1. 虚拟环境安装 1.新建虚拟机   2.虚拟机设置 2.系统历程 1.进入系统引导界面进行配置 引导项说明:            1.安装centos 系统                    ...

  3. 检查mysql表碎片化脚本

    #!/bin/sh echo -n "MySQL username: " ; read username echo -n "MySQL password: " ...

  4. (一)vim插件tabbar

    今天早晨给 TabBar.vim 的作者Groleo发了个邮件询问这个tabbar关闭失败的问题.得到的答复是 "you can use :bd instead of :close" ...

  5. 修复Windows10引导,适用gpt+uefi环境

    在双硬盘多系统安装时,容易损坏Win10的开机引导文件. 可以尝试用Windows原版安装盘启动,进入命令提示符模式: 首先使用diskpart命令确认需要修复的Windows分区的安装卷X:. 再运 ...

  6. Spire.Cloud 私有化部署教程(二)- Ubuntu 18.04 系统

    本教程主要介绍如何在Ubuntu 18.04系统上实现Spire.Cloud私有化部署.CentOS 7系统部署请参考 这篇教程. 详细步骤如下: 一.环境配置 1.关闭防火墙 1)首先查看防火墙状态 ...

  7. AJ学IOS(48)多线程网络之多线程简单了解

    AJ分享,必须精品 一:进程和线程 1:什么是进程 进程是指在系统中正在运行的一个应用程序 每个进程之间是独立的,每个进程均运行在其专用且受保护的内存空间内. 比如同时打开QQ.Xcode,系统就会分 ...

  8. [译]使用开发工具来调试 Beta 版 WebView

    自2014年以来,Android WebView 已经作为一个可更新的系统组件铺平了道路,为 Android 应用程序和用户提供了稳定性和性能改进.现代网络平台功能和安全补丁. 然而,更新可能是一把双 ...

  9. cheat sheet 简介

    cheat sheet 速查表 /小抄 如果期末考试老师只让你让带一张A4纸,合法"作弊",纸上能写多少全凭自己本事,你会写什么?大部分人应该把整个课程的知识重点梳理一遍,方便记忆 ...

  10. stand up meeting 12/11/2015

    part 组员 今日工作 工作耗时/h 明日计划 工作耗时/h UI 冯晓云 完成单词释义热度排序:允许用户自主添加释义:完成了button位置的修正(finally)和弹窗的美化:     6 tr ...