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. B 基因改造

    时间限制 : - MS   空间限制 : - KB  问题描述 "人类智慧的冰峰,只有萌萌哒的我寂寞地守望."--TBTB正走在改造人类智慧基因的路上.TB发现人类智慧基因一点也不 ...

  2. SWUST OJ 1012哈希表(链地址法处理冲突)

    哈希表(链地址法处理冲突) 1000(ms) 10000(kb) 2676 / 6911 采用除留余数法(H(key)=key %n)建立长度为n的哈希表,处理冲突用链地址法.建立链表的时候采用尾插法 ...

  3. 1089 Insert or Merge (25分)

    According to Wikipedia: Insertion sort iterates, consuming one input element each repetition, and gr ...

  4. MVC分层设计

    MVC分层设计 什么是MVC? MVC 是一种软件架构模式,利用分层的思想来设计交互式应用程序,由以下3层组成: Model 业务模型层. View 展示层. Controller 控制层. MVC包 ...

  5. java文件中出现最多的前n个单词

    将文件打开,之后每读入一次,最后按空格进行分割.存入到map里面之后进行相应的比较输出操作.并将相应的内容输出到文件里面. package com.keshangone; //将想要输出的数据写入新的 ...

  6. Jenkins构建项目后发送钉钉消息推送

    前言 钉钉是我们日常工作的沟通工具,在Jenkins构建持续集成项目配合钉钉机器人的功能,可以让我们在持续集成测试环节快速接收到测试结果的消息推送. 一:新建一个钉钉群,选择自定义机器人 二:添加机器 ...

  7. 15分钟从零开始搭建支持10w+用户的生产环境(一)

    前言 这是一个基于中小型企业或团队的架构设计. 不考虑大厂.有充分的理由相信,大厂有绝对的实力来搭建一个相当复杂的环境. 中小型企业或团队是个什么样子? 开发团队人员配置不全,部分人员身兼开发过程上下 ...

  8. Array(数组)对象-->join() 方法

    1.定义和用法 join() 方法把数组中的所有元素用指定的参数作为分隔符拼接成一个字符串. 语法: array.join(separator) 举例: var arr = [1,2,3,4,5]; ...

  9. itoa、ltoa

    #include <stdlib.h> /*整形转字符型*/ char * itoa(int value, char *string, int radix) { char tmp[33]; ...

  10. 采用TuesPechkin生成Pdf

    1.需求 前段时间有个需求,要求把网页生成pdf,找了各种插件,才决定使用这个TuesPechkin,这个是后台采用C#代码进行生成 2.做法 我要做的是一个比较简单的页面,采用MVC绑定,数据动态加 ...