java并发中的Synchronized关键词
文章目录
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关键词的更多相关文章
- Java并发编程:synchronized
Java并发编程:synchronized 虽然多线程编程极大地提高了效率,但是也会带来一定的隐患.比如说两个线程同时往一个数据库表中插入不重复的数据,就可能会导致数据库中插入了相同的数据.今天我们就 ...
- Java并发编程:Synchronized及其实现原理
Java并发编程系列: Java 并发编程:核心理论 Java并发编程:Synchronized及其实现原理 Java并发编程:Synchronized底层优化(轻量级锁.偏向锁) Java 并发编程 ...
- Java并发编程:Synchronized底层优化(偏向锁、轻量级锁)
Java并发编程系列: Java 并发编程:核心理论 Java并发编程:Synchronized及其实现原理 Java并发编程:Synchronized底层优化(轻量级锁.偏向锁) Java 并发编程 ...
- 【转】Java并发编程:synchronized
一.什么时候会出现线程安全问题? 在单线程中不会出现线程安全问题,而在多线程编程中,有可能会出现同时访问同一个资源的情况,这种资源可以是各种类型的资源:一个变量.一个对象.一个文件.一个数据库表等,而 ...
- 4、Java并发编程:synchronized
Java并发编程:synchronized 虽然多线程编程极大地提高了效率,但是也会带来一定的隐患.比如说两个线程同时往一个数据库表中插入不重复的数据,就可能会导致数据库中插入了相同的数据.今天我们就 ...
- 深入浅出Java并发中的CountDownLatch
1. CountDownLatch 正如每个Java文档所描述的那样,CountDownLatch是一个同步工具类,它允许一个或多个线程一直等待,直到其他线程的操作执行完后再执行.在Java并发中 ...
- java并发中CountDownLatch的使用
文章目录 主线程等待子线程全都结束之后再开始运行 等待所有线程都准备好再一起执行 停止CountdownLatch的await java并发中CountDownLatch的使用 在java并发中,控制 ...
- java并发中ExecutorService的使用
文章目录 创建ExecutorService 为ExecutorService分配Tasks 关闭ExecutorService Future ScheduledExecutorService Exe ...
- java并发编程(2) --Synchronized与Volatile区别
Synchronized 在多线程并发中synchronized一直是元老级别的角色.利用synchronized来实现同步具体有一下三种表现形式: 对于普通的同步方法,锁是当前实例对象. 对于静态同 ...
随机推荐
- HDU1166(线段树 +更新单点,求区间总和)、HDU1754(线段树 + 更新单点,求区间最大值)
线段树简单应用 先附上几张图便与理解,大佬文章传送门1.传送门2 HDU1166:题目描述 线段树 +更新单点,求区间总和 代码如下(递归版) #include<iostream> #in ...
- docker中MySQL镜像数据,日志,配置持久化
Docker的MySQL8镜像, 实行数据持久化 version: '3.1' services: mysql-itoken-service-admin: restart: always image: ...
- 深度解析Java中的5个“黑魔法”
现在的编程语言越来越复杂,尽管有大量的文档和书籍,这些学习资料仍然只能描述编程语言的冰山一角.而这些编程语言中的很多功能,可能被永远隐藏在黑暗角落.本文将为你解释其中5个Java中隐藏的秘密,可以称其 ...
- Hadoop(九):Shuffle组件
重温MR整体流程 工作流程 开始执行输入(InputFormat),先对文件进行分片,然后读取数据输入到Map中. Mapper读取输入内容,解析成键值对,1行内容解析成1个键值对,每个键值对调用一次 ...
- Javascript 获取随机颜色的几种方式
先认识一下颜色值的表达方式 #FFFFFF,由6位16进制数组成.#FFFFFFFF,由8位16进制数组成,前6位表示颜色,后两位数表示透明度,数值越大,透明度越小.rgb(255,255,255), ...
- C语言 文件操作(一)
#include<stdio.h> int main(){ FILE *fp = fopen("f:\\lanyue.txt","r&quo ...
- Mysql基础知识一
1.数据库的定义 数据:描述事物符号记录.(包括数字.文字.图形.图像.声音.档案记录等)以记录形式统一的格式进行存储. 广义上的数据:出现在计算机内部的一切二进制数据流都为数据 狭义上的数据:只是数 ...
- 大数据篇:Spark
大数据篇:Spark Spark是什么 Spark是一个快速(基于内存),通用,可扩展的计算引擎,采用Scala语言编写.2009年诞生于UC Berkeley(加州大学伯克利分校,CAL的AMP实验 ...
- 安装python3.8和python2.7
在同一台电脑上同时安装Python2和Python3 目前Python的两个版本Python2和Python3同时存在,且这两个版本同时在更新与维护. 到底是选择Python2还是选择Python3, ...
- echarts使用笔记
1.解决列文字隔开问题,及文字太长问题解决. yAxis: [ { type : 'category', data : message.data[0].dataone, axisLabel: { in ...