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. cardlayout

    import javax.swing.*;import java.awt.*;import java.awt.event.*;public class demo_9{    public static ...

  2. IIS Express(7.0) HTTP 错误 500.22 - Internal Server Error(vs2013)

    1.错误如下: HTTP 错误 500.22 - Internal Server Error 检测到在集成的托管管道模式下不适用的 ASP.NET 设置. 解决的方法: 首先,找到本地appcmd.x ...

  3. C语言错题集

    1.输入两个int型数a.b,求a/b的商c,不必考虑b为0的情况,输出c(保留两位小数) include<stdio.h> int main() { int a,b; float c; ...

  4. 虚拟DOM

    传统的 DOM 操作是直接在 DOM 上操作,当需要修改一系列元素中的值时,就会直接对 DOM 进行操作.如果需要操作的DOM元素过多,则成本太高,而采用 Virtual DOM 则会对需要修改的 D ...

  5. C++实现对文件中各单词词频的统计及其代码优化

    先给出github上的代码链接以及项目需求 1.项目概述 这个项目的需求可以概括为:对记事本(txt)文件进行单词的词频统计和排序,排序结果以指定格式输出到默认文件中,并要求能够快速地完成整个统计和结 ...

  6. 偏差(Bias)和方差(Variance)——机器学习中的模型选择zz

    模型性能的度量 在监督学习中,已知样本 ,要求拟合出一个模型(函数),其预测值与样本实际值的误差最小. 考虑到样本数据其实是采样,并不是真实值本身,假设真实模型(函数)是,则采样值,其中代表噪音,其均 ...

  7. HTTP二、HTTP请求处理过程的七个步骤

      HTTP02 HTTP请求处理过程的七个步骤     1.web服务处理步骤 web服务的处理过程可总结为七个步骤:   1)发起请求:客户端向服务器端发起连接请求,建立”三次握手“: 2)接收请 ...

  8. 文件上传的三种模式-Java

    文件上传的三种方式-Java 前言:因自己负责的项目(jetty内嵌启动的SpringMvc)中需要实现文件上传,而自己对java文件上传这一块未接触过,且对 Http 协议较模糊,故这次采用渐进的方 ...

  9. 洛谷P1596 [USACO10OCT]湖计数Lake Counting

    https://www.luogu.org/problemnew/show/P1596 连通块水题... 大体思路是找到是水坑的坐标然后就开始不断递归,往八个方向搜,把连在一起的都标记一遍直到找不到为 ...

  10. IOS 模拟器多开集成测试和那些坑

    #### 前言公司一直没有IOS自动化,搞得很尴尬,个人感觉搞自动测试的,不搞IOS自动化,就像金X,少了重要一点啊.也向领导申请过不止一次,总只都各种原因没有分配机器,不了了之.某天线上IOS出bu ...