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. asp.net 网站监控方案

    前言:监控web网站方法有很多种,这篇文章说一下对windows服务器 asp.net网站的监控 采用的方案,Powershell + Influxdb + Grafana 1.PowerShell ...

  2. Angular6 学习笔记——组件详解之组件通讯

    angular6.x系列的学习笔记记录,仍在不断完善中,学习地址: https://www.angular.cn/guide/template-syntax http://www.ngfans.net ...

  3. LD算法的C++实现(基于编辑距离的文本比较算法)

    算法看这里: http://www.cnblogs.com/grenet/archive/2010/06/01/1748448.html 用数组实现: #include <iostream> ...

  4. 字符串写入txt文件

    将字符串写入C盘txt文件里 File.AppendAllText(@"C:\" + DateTime.Now.ToString("HHmmss") + &qu ...

  5. iOS method swizz

    1: 防止按钮在一定时间内重复响应默认1秒 // // UIButton+AvoidDoubleClick.h // 51WaywardShop // // Created by jisa on 20 ...

  6. BS4爬取物价局房产备案价以及dataframe的操作来获取房价的信息分析

    因为最近要买房子,然后对房市做了一些调研,发现套路极多.卖房子的顾问目前基本都是一派胡言能忽悠就忽悠,所以基本他们的话是不能信的.一个楼盘一次开盘基本上都是200-300套房子,数据量虽然不大,但是其 ...

  7. 微信小程序组件化实践

    Do Not Repeat Yourself 如何提高代码质量,方法有许多:抽象.模块.组件化,我认为它们的中心点都是--Do Not Repeat Yourself. 小程序组件化 我们先看看小程序 ...

  8. J05-Java IO流总结五 《 BufferedInputStream和BufferedOutputStream 》

    1. 概念简介 BufferedInputStream和BufferedOutputStream是带缓冲区的字节输入输出处理流.它们本身并不具有IO流的读取与写入功能,只是在别的流(节点流或其他处理流 ...

  9. Flume搭建及学习(基础篇)

    转载请注明原文出处:http://www.cnblogs.com/lighten/p/6830439.html 1.简介 该文主要是翻译官方的相关文档,源地址点击这里.介绍一下Flume的一些基本知识 ...

  10. SELECT列表中的标量子查询

    发现了一种表连接新的写法,以前还没有这样写过或者见别人写过.跟同学聊天他们公司却很多人这样写,看来真的要学学sql了 表 CREATE TABLE `t_book` ( `FId` ) NOT NUL ...