synchronized

java课上讲到过synchronized

首先看看用synchronized和没用synchronized的区别

import lombok.Getter;
/**
* @author yintianhao
* @createTime 20190123 16:28
* @description synchronized
*/
public class SYN {
@Getter
private int count;
private Object lock;
public SYN(){
count = 0;
lock = new Object();
}
public void noSyn(){
for (int i = 0;i < 100;i++){
count++;
}
}
public void Syn(){
synchronized (lock){
for (int i = 0;i < 100;i++){
count++;
}
}
}
}

要进行的操作是对count进行自增操作,执行一次里面的Syn和noSyn函数都是对count这个变量进行加一百次的操作

不同的就是,Syn函数用了synchronized

然后开启十个线程来执行这两个函数,之后打印出count的值,我们期望的是count等于1000

List<Thread> threads = new ArrayList<>();
SYN syn = new SYN();
for (int i = 0;i < 10;i++){
threads.add(new Thread(()->syn.noSyn(),"thread-"+i));
}
for (Thread o:threads)
o.start();
for (Thread o:threads)
o.join();
System.out.println(syn.getCount());

再看运行结果

可是结果却不是1000

然后再把运行的函数改成Syn(),再次看结果

1000符合预期,为了避免偶然,重复运行几次结果仍是1000

那么为什么这里结果不同的呢,原因就是牵涉到另外一个概念,锁,在这个例子中,SYN类中的lock对象就可以看做一把锁

只有拿到锁,才能执行synchronized代码块中的代码块,所以当一个线程在执行synchronized里面的代码并且还没把锁交出来(释放)时,其他线程无法获取

到锁,故无法执行其中的代码,在没有使用synchronized的函数中,因为没有锁机制,有可能for循环还没结束的时候就有新的进程进来,即没有加到100就进来

故count最后不会到1000,而且也不是一个固定的数字

synchronized的实现原理

synchronized有三种用法:

第一种是对于同步方法,即修饰某个函数,这个时候锁对象是当前类的实例化对象

第二种是对于同步静态方法,这个时候锁是当前类的Class对象

第三种就是我上面的用法,对于同步代码块,锁是括号里的对象

前面说一个进程会获得锁,那么这个锁是存在在什么地方呢

首先需要了解java对象头,对象头分为两种

普通对象的对象头占两个字宽

数组对象的对象头占三个字宽,相比于普通对象的对象头多了一个字宽来存储数组长度

java对象头中的Markword字段中存储对象的HashCode,分代年龄和锁标记位,在运行期间,MarkWord存储的数据会随着锁标志位

的变化为变化,MarkWord的结构是这个样子的

这个锁的标志位就是锁的类型了,也就是之前所说的"锁"

Volatile

java对volatile的定义是:Java编程语言允许线程访问共享变量,为了确保共享变量能被准确和一致地更新,线程应该确保通过排他锁单独获得这个变量,

如果一个字段被申明为volatile,线程内存模型确保所有线程能够看到的这个变量的值是一致的

那么volatile是怎么保证可见性的呢

我们知道处理器为了保证处理的速度,是不和系统内存直接通信的,因为内存的速度远远慢yu每个处理器先是将系统内存中的数据读入到CPU内部缓存中

再进行操作,但是操作完成之后是不知道什么时候缓存中的数据会写到内存中的,那么其他处理器读取这个变量的时候就有可能读取到旧的数据,volatile是

这样子做的,一旦被volatile修饰的变量发生读写操作,就会发生两个动作:

1,将当前处理器缓存行的数据写到系统内存中(这是Lock前缀指令会引起的)

2,然后这个操作使得其他CPU缓存了该内存地址的数据无效

然后我们知道的是,每个处理器中的缓存是一致的,那么这个时候就需要缓存一致性协议,每个处理器嗅探总线上传播的数据来检测自己缓存中的值是否过期,

当发现自己的缓存行对应的内存地址被修改,就会将自己缓存行设置为无效,当需要修改的时候,重新从系统内存读取到缓存行,这样就实现了可见性

关于volatile变量的原子性,单个volatile变量的读写是具有原子性的,但是如果是类似于上面代码中的++这种复合操作,则不具有原子性

volatile和synchronized关键字的更多相关文章

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

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

  2. volatile与synchronized关键字

    volatile关键字相信了解Java多线程的读者都很清楚它的作用.volatile关键字用于声明简单类型变量,如int.float.boolean等数据类型.如果这些简单数据类型声明为volatil ...

  3. 《Java基础知识》Java锁详解(volatile,synchronized等)

    volatile: 让变量每次在使用的时候,都从主存中取. volatile具有synchronized关键字的“可见性”,但是没有synchronized关键字的“并发正确性”,也就是说不保证线程执 ...

  4. java中的volatile和synchronized

    关于volatile和同步相关的东西,网上有太多错误和解释不清的东西, 所以查阅相关书籍和文章后总结如下, 如果还是也存在不正确的内容,请一定要指出来, 以免误人子弟:) 1. 原子性与可视性 原子性 ...

  5. volatile和synchronized到底啥区别?多图文讲解告诉你

    你有一个思想,我有一个思想,我们交换后,一个人就有两个思想 If you can NOT explain it simply, you do NOT understand it well enough ...

  6. volatile关键字和synchronized关键字

    volatile关键字: 可以用来修饰字段(成员变量),就是告知程序任何对该变量的访问均需要从共享内存中获取,而对它的改变必须同步刷新回共享内存,它能保证所有线程对变量访问的可见性. synchron ...

  7. 并发编程之ThreadLocal、Volatile、synchronized、Atomic关键字扫盲

    前言 对于ThreadLocal.Volatile.synchronized.Atomic这四个关键字,我想一提及到大家肯定都想到的是解决在多线程并发环境下资源的共享问题,但是要细说每一个的特点.区别 ...

  8. 并发系列2:Java并发的基石,volatile关键字、synchronized关键字、乐观锁CAS操作

    由并发大师Doug Lea操刀的并发包Concurrent是并发编程的重要包,而并发包的基石又是volatile关键字.synchronized关键字.乐观锁CAS操作这些基础.因此了解他们的原理对我 ...

  9. 多线程的指令重排问题:as-if-serial语义,happens-before语义;volatile关键字,volatile和synchronized的区别

    一.指令重排问题 你写的代码有可能,根本没有按照你期望的顺序执行,因为编译器和 CPU 会尝试指令重排来让代码运行更高效,这就是指令重排. 1.1 虚拟机层面 我们都知道CPU执行指令的时候,访问内存 ...

随机推荐

  1. OO学期总结

    一.测试与正确性论证差异对比 测试,顾名思义,就是用一些有意义或无意义的输入去检测程序的正确性或鲁棒性,因其直观明了所以在写简单的程序时我们能迅速找出bug并加以解决.并且,这种方式是绝对客观的,只要 ...

  2. ArrayAdapter构造方法中的textViewResourseId

    simple_list_item_1:每个列表项都是一个普通的textView simple_list_item_2:每个列表项都是一个普通的textView(字体略大) simple_list_it ...

  3. 解决 ERROR: missing Change-Id in commit message footer 问题

    提交代码操作 git push origin HEAD:refs/for/XXX,提示失败ERROR: missing Change-Id in commit message footer,丢失Cha ...

  4. 《Miracle-House团队》项目需求分析改进

    (一)团队项目需求分析改进 一.<西小餐项目需求规格说明书>的不足 通过老师和其他同学的指正和建议,我们发现上次的需求规格说明书存在以下不足: 1.需求规格文档不够完整和规范: 2.系统设 ...

  5. [C#.net]SQL参数传入空值报错解决方案

    C#中的null与SQL中的NULL是不一样的,SQL中的NULL用C#表示出来就是DBNull.Value. 注意:SQL参数是不能接受C#的null值的,传入null就会报错. SqlComman ...

  6. asp.net core web 项目附加进程调试

    之前asp.net web项目在部署IIS站点的时候可以直接选择项目目录,不用发布,然后附加进程的时候,找到w3wp.exe开头的进程,再根据用户名找到要附加的进程,就可以附加进程调试了.但asp.n ...

  7. C/C++字符串相关知识使用整理

    C++字符串处理有最原始的char以及string两种方式,这里对其常用的功能进行总结. #include <string>using namespace std; ]; string s ...

  8. linux下PythonQt混编记录

    看了很多博主经验,然后自己实验总结出来的,就不一一写出处了,非常感谢各位博主的分享经验. 一.安装Python3.6 安装依赖环境 # yum -y install zlib-devel bzip2- ...

  9. Git系列:第七篇-Maven项目下提交时忽略不必要的文件或文件夹

    用.gitignore文件来进行忽略不必要的文件或文件夹 在开发中我们要提交的内容大都是src里的全部文件(java文件).gitignore(忽略文件)pom.xml(maven配置文件)----- ...

  10. web专业课学习及往后方向发展

    日常10点起床!!!! web主要是网页设计,目前自我方向是学习web前端开发,熟悉掌握相关的编辑应用已达到能设计出满意的网页,日后继续学习后端等 ,成为全栈工程师.