JMM关于synchronized的两条规定:

  1)线程解锁前,必须把共享变量的最新值刷新到主内存中

  2)线程加锁时,将清空工作内存中共享变量的值,从而使用共享变量时需要从主内存中重新获取最新的值

   (注意:加锁与解锁需要是同一把锁)

通过以上两点,可以看到synchronized能够实现可见性。同时,由于synchronized具有同步锁,所以它也具有原子性

  

多线程中程序交错执行时,重排序可能会造成内存可见性问题

接下来我们看一段代码:

/**
* synchronized能够实现原子性(同步)、可见性
*
* @author xuwenjin
*/
public class SynchronizedDemo { //共享变量
private boolean ready = false;
private int result = ;
private int number = ; /**
* 写操作
*/
public void write() {
ready = true; //1.1
number = ; //1.2
} /**
* 读操作
*/
public void read() {
if (ready) { //2.1
result = number * ; //2.2
}
System.out.println("result:" + result);
} //内部线程类
private class WriteReadThread extends Thread { private boolean flag = false; public WriteReadThread(boolean flag){
this.flag = flag;
} @Override
public void run() {
if (flag) {
write();
}else {
read();
}
}
} public static void main(String[] args) {
SynchronizedDemo demo = new SynchronizedDemo();
//启动线程执行写操作
demo.new WriteReadThread(true).start();
//启动线程执行读操作
demo.new WriteReadThread(false).start();
} }

上面的代码可能出现如下执行顺序:

  1) 1.1 --> 1.2 --> 2.1--> 2.2       result的值为 (正常情况)

  2) 1.1 --> 2.1 --> 2.2 --> 1.2       result的值为 (当写线程执行完1.1之后,读线程开始)

  3) 1.2 --> 2.1 --> 2.2 --> 1.1       result的值为 (1.1跟1.2重排序)

  4)...

当然由于重排序和线程的交叉执行,还可能出现很多种执行顺序

导致共享变量在线程间不可见的原因:

  a、线程的异步执行

  b、重排序结合线程交叉执行

  c、共享变量更新后的值没有在工作内存与主内存间及时更新

那么如何解决可见性的问题呢?接下来我们的主角出场:synchronized

安全的代码:

    /**
* 写操作
*/
public synchronized void write() {
ready = true; //1.1
number = ; //1.2
} /**
* 读操作
*/
public synchronized void read() {
if (ready) { //2.1
result = number * ; //2.2
}
System.out.println("result:" + result);
}

由于synchronized的原子性、可见性,可以完美解决以上说的三点问题。不过读线程和写线程的执行顺序是不定的,所以result的结果仍然会出现6或0。

如何保证线程顺序执行,大家可参考:https://blog.csdn.net/wenxingchen/article/details/78026767

synchronized实现可见性的更多相关文章

  1. synchronized的可见性理解

    之前的时候看<并发编程的艺术>,书中提到dcl写法的单例模式是有问题的,有可能会导致调用者得到一个创建了一半的对象,从而导致报错.修复办法是将单例对象的引用添加volatile进行修饰,禁 ...

  2. java synchronized实现可见性对比volatile

    问题: 大家可以先看看这个问题,看看这个是否有问题呢? 那里有问题呢? public class ThreadSafeCache { int result; public int getResult( ...

  3. 关于synchronized 影响可见性的问题

    问题来自于学习thinking in java的时候的一个示例,先上代码吧 public class StopThread { private static boolean stop = false; ...

  4. Volatile和Synchronized对可见性和原子性的支持

    在学习并发编程的时候,遇见了volatile和synchronized关键字问题,volatile是可以保证可见性,但无法保证原子性,synchronized关键字由于其是加锁机制,肯定是可以保证原子 ...

  5. synchronized内存可见性理解

    一.背景 最近在看<Java并发编程实战>这本书,看到共享变量的可见性,其中说到"加锁的含义不仅仅局限于互斥行为,还包括内存可见性". 我对于内存可见性第一反应是vol ...

  6. java线程-synchronized实现可见性代码

    以下是一个普通线程代码: package com.Sychronized; public class SychronizedDemo { //共享变量 private boolean ready=fa ...

  7. volatile、Synchronized实现变量可见性的原理,volatile使用注意事项

    变量不可见的两个原因 Java每个线程工作都有一个工作空间,需要的变量都是从主存中加载进来的.Java内存模型如下(JMM): 线程访问一个共享的变量时,都需要先从主存中加载一个副本到自己的工作内存中 ...

  8. 1 Java线程的内存可见性

    Java内存的可见性 可见性: 一个线程对共享变量的修改,能够及时被其它线程看到 共享变量: 如果一个变量在多个线程的工作内存中都存在副本,那么这个变量就是这几个线程的共享变量 Java内存模型(JM ...

  9. 细说Java多线程之内存可见性

    编程这些实践的知识技能,每一次学习使用可能都会有新的认识 一.细说Java多线程之内存可见性(数据挣用)         1.共享变量在线程间的可见性                共享变量:如果一个 ...

随机推荐

  1. 深入理解Aspnet Core之Identity(2)

    主题: 我将继续介绍Identity的账户简单管理,即是增删改查.我会只介绍增加和删除,修改功能代码我会上传到我的github上, 创建用户: 1.我在Model文件夹创建一个 CreateModel ...

  2. C# AutoMapper 了解一下

    什么是AutoMapper? 简单来说就是将一个对象映射到另一个对象的代码. 摆脱了繁琐的赋值过程 (最常见也就是Model -——ViewModel) AutoMapper安装 我使用的是VS201 ...

  3. CentOS 6 - 升级内核

    有的时候,需要升级Linux内核,今天我就是在CentOS 6中升级内核,在没有升级内核之前,我的CentOS 6只有2.6.32这一个内核,也是默认启动的内核.下面就开始一步步操作升级内核了! 一, ...

  4. 5.python内置函数详解

    内置函数 声明,转载至这位大哥,感谢之至 http://blog.csdn.net/oaa608868/article/details/53506188 关于分类 数学运算(7个) 类型转换(24个) ...

  5. jzoj3363

    JYY 来到了一个新的城市,为了和大家保持联系,第一件事就是办理新的手机号.JYY 对号码的要求很高,希望大家都能够顺畅地阅读手机号,因此 JYY 特别研究了地球人的电话号码阅读习惯,有如下重大发现 ...

  6. [underscore源码学习]——`>>` 运算符和二分查找

    这是一篇记录学习 underscore v0.0.5 的fragment,觉得有点意思,和大家分享一下. 先看_.sortedIndex的源码,它用来确定 obj 在 array中的位置(array升 ...

  7. java对象的结构

    [Java对象解析]不得不了解的对象头 一个Java对象到底占用多大内存? JVM源码分析之java对象头实现 java对象在内存中的结构(转帖) 一个Java对象到底占多大内存? 在Hotspot ...

  8. MySQL多实例(二)

    一.多实例MySQL数据库原理 1.1:原理图 1.2:多实例原理(什么是多实例) 简单来说MySQL多实例就是在一台服务器上同时开启多个不用的服务端口(如:3306.3307),同时运行多个MySQ ...

  9. POJ 1126

    #include <stdio.h> #include <string> #include <iostream> using namespace std; int ...

  10. 面试题:js如何渲染十万条数据并不卡住界面

    这道题考察了如何在不卡住页面的情况下渲染数据,也就是说不能一次性将几万条都渲染出来,而应该一次渲染部分 DOM,那么就可以通过 requestAnimationFrame 来每 16 ms 刷新一次. ...