并发之synchronized关键字的应用

synchronized关键字理论基础

前两章我们学习了下java内存模型的相关知识, 现在我们来讲讲逢并发必出现的synchronized关键字。

作用

synchronized是Java中的关键字,是一种同步锁。依赖JVM实现。

JMM对synchronized约束

  1. 线程解锁前,必须将变量的最新值刷新回主内存。

  2. 线程加锁时,将情况工作内存中变量的共享值,从而使变量从主内存中读取最新的值。

注意:加锁和解锁的锁必须是同一把锁。

synchronized关键字应用方向

它修饰的对象有以下几种:

1.修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象;

2.修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象;

3.修改一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象;

4.修改一个类,其作用的范围是synchronized后面括号括起来的部分,作用主的对象是这个类的所有对象。

并发测试常用类:

线程池创建方式:

ExecutorService 线程池,每一个线程代表一次并发。

ExecutorService executorService =Executors.newCachedThreadPool();

模拟并发次数:

Semaphore 同一时间可以一同运行的线程数量。

Semaphore semaphore = new Semaphore(threadTotal);

模拟并发总量:

CountDownLatch 运行多少个线程后才能再次往下执行、

CountDownLatch countDownLatch = new CountDownLatch(clientTotal);

实际应用

修饰代码块

/**
* 同步代码块
*/
@Slf4j
public class SyncCodeBlock {
private static final int COUNT = 5; public void syncCodeBlock(String block) {
synchronized (this){
for(int i =0;i<COUNT;i++){
log.info("同步块{}并发-{}",block,i);
}
}
for(int i =0;i<COUNT;i++){
log.info("异步块{}并发-{}",block,i);
} }
public void asynCodeBlock(int block) {
for(int i =0;i<COUNT;i++){
log.info("代码块{}并发-{}",block,i);
}
} public static void main(String[] args) {
ExecutorService executorService =Executors.newCachedThreadPool();
SyncCodeBlock syncCodeBlock = new SyncCodeBlock();
executorService.execute(()->{
syncCodeBlock.syncCodeBlock("A");
});
executorService.execute(()->{
syncCodeBlock.syncCodeBlock("B");
});
}
}

结果

同步块A并发0

同步块A并发1

同步块A并发2

同步块A并发3

同步块A并发4

异步块A并发0

异步块A并发1

异步块A并发2

异步块A并发3

同步块B并发0

同步块B并发1

同步块B并发2

同步块B并发3

同步块B并发4

异步块B并发0

异步块B并发1

异步块A并发4

异步块B并发2

异步块B并发3

异步块B并发4

A线程执行同步代码块时并没有B线程干扰,说明A线程锁住了对象。

A线程执行完同步之后释放了锁,B的同步异步代码块和A的异步代码块才开始执行。

由上述例子可以证明

同步代码块作用范围只在synchronized{}括起来的部分。而锁定锁定的是这个对象本身。

**

@Slf4j
public class SyncMethod {
private static final int COUNT = 5; public synchronized void syncMethod(String block) {
for(int i =0;i<COUNT;i++){
// log.info("同步{}并发-{}",block,i);
System.out.println("同步"+block+"并发"+i);
}
}
public void asynMethod(String block) {
for(int i =0;i<COUNT;i++){
// log.info("异步块{}并发-{}",block,i);
System.out.println("异步"+block+"并发"+i);
}
} public static void main(String[] args) {
ExecutorService executorService = Executors.newCachedThreadPool();
SyncMethod syncMethod = new SyncMethod();
executorService.execute(()->{
syncMethod.syncMethod("A"); });
executorService.execute(()->{
syncMethod.syncMethod("B");
});
}
}

作用于方法

同步A并发0

同步A并发1

同步A并发2

同步A并发3

同步A并发4

同步B并发0

同步B并发1

同步B并发2

同步B并发3

同步B并发4

A线程执行同步代码是连续的,并没有B参入。说明锁住了对象

A线程执行完成后B线程执行自己的锁定方法。

上述例子说明作:

同步的作用范围是整个方法而锁定的是整个方法所在对象那个的本身

作用于静态方法、类

public class SyncStaticMethod {
private static final int COUNT = 10; public synchronized static void syncStaticMethod(String block){
for(int i =0;i<COUNT;i++){
System.out.println("静态同步"+block+"并发"+i);
}
} public static void asynStaticMethod(String block){
for(int i =0;i<COUNT;i++){
System.out.println("静态异步"+block+"并发"+i);
}
} public static void main(String[] args) {
ExecutorService executorService = Executors.newCachedThreadPool();
for(int j= 0;j<10;j++){
int finalJ = j;
executorService.execute(() -> {
SyncStaticMethod.syncStaticMethod(""+ finalJ);
});
} } }

添加关键字效果

静态同步0并发0

静态同步0并发1

静态同步0并发2

静态同步0并发3

静态同步0并发4

静态同步0并发5

静态同步0并发6

静态同步0并发7

静态同步0并发8

静态同步0并发9

静态同步2并发0

静态同步2并发1

静态同步2并发2

静态同步2并发3

静态同步2并发4

静态同步2并发5

静态同步2并发6

静态同步2并发7

静态同步2并发8

静态同步2并发9

静态同步1并发0

静态同步1并发1

静态同步1并发2

静态同步1并发3

静态同步1并发4

静态同步1并发5

静态同步1并发6

静态同步1并发7

静态同步1并发8

静态同步1并发9

静态同步3并发0

静态同步3并发1

静态同步3并发2

静态同步3并发3

静态同步3并发4

静态同步3并发5

静态同步3并发6

静态同步3并发7

静态同步3并发8

静态同步3并发9

静态同步6并发0

静态同步6并发1

静态同步6并发2

静态同步6并发3

静态同步6并发4

静态同步6并发5

静态同步6并发6

静态同步6并发7

静态同步6并发8

静态同步6并发9

静态同步5并发0

静态同步5并发1

静态同步5并发2

静态同步5并发3

静态同步5并发4

静态同步5并发5

静态同步5并发6

静态同步5并发7

静态同步5并发8

静态同步5并发9

静态同步4并发0

静态同步4并发1

静态同步4并发2

静态同步4并发3

静态同步4并发4

静态同步4并发5

静态同步4并发6

静态同步4并发7

静态同步4并发8

静态同步4并发9

静态同步9并发0

静态同步9并发1

静态同步9并发2

静态同步9并发3

静态同步9并发4

静态同步9并发5

静态同步9并发6

静态同步9并发7

静态同步9并发8

静态同步9并发9

静态同步8并发0

静态同步8并发1

静态同步8并发2

静态同步8并发3

静态同步8并发4

静态同步8并发5

静态同步8并发6

静态同步8并发7

静态同步8并发8

静态同步8并发9

静态同步7并发0

静态同步7并发1

静态同步7并发2

静态同步7并发3

静态同步7并发4

静态同步7并发5

静态同步7并发6

静态同步7并发7

静态同步7并发8

静态同步7并发9

静态同步0并发0

静态同步0并发1

静态同步0并发2

静态同步0并发3

静态同步0并发4

静态同步0并发5

静态同步0并发6

静态同步0并发7

静态同步0并发8

静态同步0并发9

静态同步2并发0

静态同步2并发1

静态同步2并发2

静态同步2并发3

静态同步2并发4

静态同步2并发5

静态同步2并发6

静态同步2并发7

静态同步2并发8

静态同步2并发9

静态同步1并发0

静态同步1并发1

静态同步1并发2

静态同步1并发3

静态同步1并发4

静态同步1并发5

静态同步1并发6

静态同步1并发7

静态同步1并发8

静态同步1并发9

静态同步3并发0

静态同步3并发1

静态同步3并发2

静态同步3并发3

静态同步3并发4

静态同步3并发5

静态同步3并发6

静态同步3并发7

静态同步3并发8

静态同步3并发9

静态同步6并发0

静态同步6并发1

静态同步6并发2

静态同步6并发3

静态同步6并发4

静态同步6并发5

静态同步6并发6

静态同步6并发7

静态同步6并发8

静态同步6并发9

静态同步5并发0

静态同步5并发1

静态同步5并发2

静态同步5并发3

静态同步5并发4

静态同步5并发5

静态同步5并发6

静态同步5并发7

静态同步5并发8

静态同步5并发9

静态同步4并发0

静态同步4并发1

静态同步4并发2

静态同步4并发3

静态同步4并发4

静态同步4并发5

静态同步4并发6

静态同步4并发7

静态同步4并发8

静态同步4并发9

静态同步9并发0

静态同步9并发1

静态同步9并发2

静态同步9并发3

静态同步9并发4

静态同步9并发5

静态同步9并发6

静态同步9并发7

静态同步9并发8

静态同步9并发9

静态同步8并发0

静态同步8并发1

静态同步8并发2

静态同步8并发3

静态同步8并发4

静态同步8并发5

静态同步8并发6

静态同步8并发7

静态同步8并发8

静态同步8并发9

静态同步7并发0

静态同步7并发1

静态同步7并发2

静态同步7并发3

静态同步7并发4

静态同步7并发5

静态同步7并发6

静态同步7并发7

静态同步7并发8

静态同步7并发9

public class SyncStaticMethod {
private static final int COUNT = 10; public synchronized static void syncStaticMethod(String block){
for(int i =0;i<COUNT;i++){
System.out.println("静态同步"+block+"并发"+i);
}
} public static void asynStaticMethod(String block){
for(int i =0;i<COUNT;i++){
System.out.println("静态异步"+block+"并发"+i);
}
} public static void main(String[] args) {
ExecutorService executorService = Executors.newCachedThreadPool();
for(int j= 0;j<10;j++){
int finalJ = j;
executorService.execute(() -> {
SyncStaticMethod.asynStaticMethod(""+ finalJ);
});
} } }

不添加关键字静态方法

静态异步0并发0

静态异步0并发1

静态异步0并发2

静态异步0并发3

静态异步0并发4

静态异步0并发5

静态异步0并发6

静态异步0并发7

静态异步0并发8

静态异步0并发9

静态异步1并发0

静态异步1并发1

静态异步1并发2

静态异步1并发3

静态异步1并发4

静态异步1并发5

静态异步1并发6

静态异步1并发7

静态异步1并发8

静态异步1并发9

静态异步2并发0

静态异步3并发0

静态异步3并发1

静态异步2并发1

静态异步2并发2

静态异步3并发2

静态异步3并发3

静态异步2并发3

静态异步2并发4

静态异步2并发5

静态异步2并发6

静态异步3并发4

静态异步3并发5

静态异步3并发6

静态异步3并发7

静态异步3并发8

静态异步3并发9

静态异步2并发7

静态异步2并发8

静态异步2并发9

静态异步4并发0

静态异步4并发1

静态异步4并发2

静态异步4并发3

静态异步4并发4

静态异步4并发5

静态异步4并发6

静态异步4并发7

静态异步5并发0

静态异步6并发0

静态异步6并发1

静态异步6并发2

静态异步6并发3

静态异步6并发4

静态异步6并发5

静态异步6并发6

静态异步4并发8

静态异步4并发9

静态异步6并发7

静态异步6并发8

静态异步5并发1

静态异步5并发2

静态异步5并发3

静态异步5并发4

静态异步5并发5

静态异步5并发6

静态异步5并发7

静态异步6并发9

静态异步5并发8

静态异步5并发9

静态异步7并发0

静态异步7并发1

静态异步7并发2

静态异步7并发3

静态异步7并发4

静态异步7并发5

静态异步7并发6

静态异步8并发0

静态异步8并发1

静态异步8并发2

静态异步8并发3

静态异步8并发4

静态异步8并发5

静态异步9并发0

静态异步9并发1

静态异步9并发2

静态异步7并发7

静态异步7并发8

静态异步7并发9

静态异步9并发3

静态异步8并发6

静态异步8并发7

静态异步8并发8

静态异步8并发9

静态异步9并发4

静态异步9并发5

静态异步9并发6

静态异步9并发7

静态异步9并发8

静态异步9并发9

一个带有成员变量的demo

public class SyncExample {

    static final int clientTotal = 30000;
static final int threadTotal = 300;
static int count = 0; synchronized void add() {
count++;
} public static void main(String[] args) throws Exception {
SyncExample syncExample = new SyncExample();
ExecutorService executorService = Executors.newCachedThreadPool();
Semaphore semaphore = new Semaphore(threadTotal);
CountDownLatch countDownLatch = new CountDownLatch(clientTotal); for(int i =0;i<clientTotal;i++){ executorService.execute(()->{
try {
semaphore.acquire();
syncExample.add();
semaphore.release();
} catch (Exception e) {
}
countDownLatch.countDown();
});
}
countDownLatch.await();
executorService.shutdown();
System.out.println("总计执行:"+count);
}
}

总结

synchronized 修饰类型 作用范围 锁定对象 实现
作用于代码块 大括号{}括起来的代码 调用代码块的对象 synchronized(this){...}
作用于方法 整个方法 调用代码块的对象 public synchronized void xxx(){...}
作用于静态方法 静态方法 该类所有对象 public static synchronized void xxx(){...}
作用于类 synchronized后面括号括起来的部分 该类所有对象 synchronized(xxx.class){...}

注意:继承并不能使子类继承synchronized关键字,synchronized不属于方法声明的一部分。如需同步需要自己再次添加,

并发之synchronized关键字的应用的更多相关文章

  1. Java并发之synchronized关键字深度解析(二)

    前言 本文继续[Java并发之synchronized关键字深度解析(一)]一文而来,着重介绍synchronized几种锁的特性. 一.对象头结构及锁状态标识 synchronized关键字是如何实 ...

  2. Java并发之synchronized关键字

         上篇文章我们主要介绍了并发的基本思想以及线程的基本知识,通过多线程我们可以实现对计算机资源的充分利用,但是在最后我们也说明了多线程给程序带来的两种典型的问题,针对它们,synchronize ...

  3. Java并发之synchronized关键字和Lock接口

    欢迎点赞阅读,一同学习交流,有疑问请留言 . GitHub上也有开源 JavaHouse,欢迎star 引用 当开发过程中,我们遇到并发问题.怎么解决? 一种解决方式,简单粗暴:上锁.将千军万马都给拦 ...

  4. Java并发之synchronized关键字深度解析(三)

    前言 本篇主要介绍一下synchronized的批量重偏向和批量撤销机制,属于深水区,大家提前备好氧气瓶. 上一篇说完synchronized锁的膨胀过程,下面我们再延伸一下synchronized锁 ...

  5. Java并发之synchronized关键字深度解析(一)

    前言 近期研读路神之绝世武学,徜徉于浩瀚无垠知识之海洋,偶有攫取吉光片羽,惶恐未领略其精髓即隐入岁月深处,遂急忙记录一二,顺备来日吹cow之谈资.本小系列为并发之亲儿子-独臂狂侠synchronize ...

  6. 深入理解Java并发之synchronized实现原理

    深入理解Java类型信息(Class对象)与反射机制 深入理解Java枚举类型(enum) 深入理解Java注解类型(@Annotation) 深入理解Java类加载器(ClassLoader) 深入 ...

  7. 《提升能力,涨薪可待》—Java并发之Synchronized

    Synchronized简介 线程安全是并发编程中的至关重要的,造成线程安全问题的主要原因: 临界资源, 存在共享数据 多线程共同操作共享数据 而Java关键字synchronized,为多线程场景下 ...

  8. 从JAVA看C#中volatile和synchronized关键字的作用

    最近一直在想C#中 volatile关键字到底是用来干什么的?查了很多.NET的文章都是说用volatile修饰的变量可以让多线程同时修改,这是什么鬼... 然后查到了下面这篇JAVA中关于volat ...

  9. Java多线程系列--“基础篇”04之 synchronized关键字

    概要 本章,会对synchronized关键字进行介绍.涉及到的内容包括:1. synchronized原理2. synchronized基本规则3. synchronized方法 和 synchro ...

随机推荐

  1. WCF开发实战系列二:使用IIS发布WCF服务

    WCF开发实战系列二:使用IIS发布WCF服务 (原创:灰灰虫的家http://hi.baidu.com/grayworm) 上一篇中,我们创建了一个简单的WCF服务,在测试的时候,我们使用VS200 ...

  2. maveb安装与配置(win10)

    转载:https://www.cnblogs.com/eagle6688/p/7838224.html 看了几篇博客,感觉这篇博客写的含金量最高了,因为我电脑的系统是win10的,所以配置有细微的差别 ...

  3. python中的os模块

    os模块 os模块的作用: os,语义为操作系统,所以肯定就是操作系统相关的功能了,可以处理文件和目录这些我们日常手动需要做的操作,就比如说:显示当前目录下所有文件/删除某个文件/获取文件大小…… 另 ...

  4. zabbix3.x添加H3C网络设备详解

    zabbix3.x添加H3C网络设备详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 前言: 欢迎加入:高级运维工程师之路 598432640 相信大家在看我的文章之前,也看过其 ...

  5. Log4net(一)-——配置文件

    一.Log4Net框架介绍 Log4net 是 Apache 下一个开放源码的项目,它是Log4j 的一个克隆版.Log4net中定义了多种日志信息输出模式.它可以根据需要将日志输出到控制台,文本文件 ...

  6. 缓存穿透、雪崩、热点与Redis

    (拼多多问:Redis雪崩解决办法) 导读:互联网系统中不可避免要大量用到缓存,在缓存的使用过程中,架构师需要注意哪些问题?本文以 Redis 为例,详细探讨了最关键的 3 个问题. 一.缓存穿透预防 ...

  7. Linux 命令详解(九)轻易删除OpenSSL 的后果

    警告自己,不要轻易的去删除系统的软件 1.composer自动更新出现错误 www@TinywanAliYun:~/web/go-study-line$ composer self-update Ke ...

  8. Hyper-V和其他虚拟机共存 【转】

    由于Windows中Hyper-V的实现方式在系统中为独占,所以其不能与其他的虚拟机共存. 下面的方法是在系统中新增一个启动项,在这个启动项中关闭Hyper-V,这样就可以安装并使用其他虚拟机了.需要 ...

  9. VC++中LogFont设置字体(转)

    LOGFONT是Windows内部字体的逻辑结构,主要用于设置字体格式,其定义如下:typedef struct tagLOGFONTA{LONG lfHeight;LONG lfWidth;LONG ...

  10. Linux - 服务基础

    /etc/init.d/sendmail start # 启动服务 /etc/init.d/sendmail stop # 关闭服务 /etc/init.d/sendmail status # 查看服 ...