关于synchronized 影响可见性的问题
问题来自于学习thinking in java的时候的一个示例,先上代码吧
public class StopThread {
private static boolean stop = false;
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(new Runnable(){
public void run() {
int i = 0;
while (!stop) {
i++;
}
}
});
t.start();
TimeUnit.SECONDS.sleep(1);
stop = true;
}
}
毫无疑问,这段代码会永远的执行下去,因为后台线程感觉不到主线程已经改变了stop,
然后我习惯性的在while循环中打印了下i(syso)
然后运行,发现程序在运行了一秒左右就停止了!!
我一脸懵逼,然后看了下syso的代码,发现有一段同步块
public void println(int x) {
synchronized (this) {
print(x);
newLine();
}
}
然后我也在代码里尝试着加了一个空的同步块,发现也会停止
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(new Runnable(){
@Override
public void run() {
int i = 0;
Object lock = new Object();
long start = System.nanoTime();
while (!stop) {
i++;
synchronized (lock) {
// nothing
}
}
long end = System.nanoTime();
Duration d = Duration.ofNanos(end - start);
System.out.println(d.toMillis() + "ms");
}
});
t.start();
TimeUnit.SECONDS.sleep(1);
stop = true;
}
运行结果是 1000ms
那么问题来了,synchronized 到底干了什么。。
按理说,synchronized 只会保证该同步块中的变量的可见性,发生变化后立即同步到主存,但是,stop变量并不在同步块中
实际上,JVM对于现代的机器做了最大程度的优化,也就是说,最大程度的保障了线程和主存之间的及时的同步,也就是相当于虚拟机尽可能的帮我们加了个volatile,但是,当CPU被一直占用的时候,同步就会出现不及时,也就出现了后台线程一直不结束的情况。
举个例子,在while循环中sleep一下,程序会很快的结束,sleep方法中并没有同步代码块
public void run() {
int i = 0;
long start = System.nanoTime();
while (!stop) {
i++;
try {
TimeUnit.MILLISECONDS.sleep(10);
} catch (InterruptedException e) {
}
}
long end = System.nanoTime();
Duration d = Duration.ofNanos(end - start);
System.out.println(d.toMillis() + "ms");
}
再举个栗子,在while循环中做一些耗时但不耗CPU的操作,也会结束的很快,因为这个时候CPU空闲了,JVM就有机会尽快的将主存和栈变量同步
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(new Runnable(){
@Override
public void run() {
int i = 0;
long start = System.nanoTime();
while (!stop) {
i++;
Object[] arr = new Object[1000000];
}
long end = System.nanoTime();
Duration d = Duration.ofNanos(end - start);
System.out.println(d.toMillis() + "ms");
}
});
t.start();
TimeUnit.SECONDS.sleep(1);
stop = true;
}
关于synchronized 影响可见性的问题的更多相关文章
- synchronized的可见性理解
之前的时候看<并发编程的艺术>,书中提到dcl写法的单例模式是有问题的,有可能会导致调用者得到一个创建了一半的对象,从而导致报错.修复办法是将单例对象的引用添加volatile进行修饰,禁 ...
- java synchronized实现可见性对比volatile
问题: 大家可以先看看这个问题,看看这个是否有问题呢? 那里有问题呢? public class ThreadSafeCache { int result; public int getResult( ...
- Volatile和Synchronized对可见性和原子性的支持
在学习并发编程的时候,遇见了volatile和synchronized关键字问题,volatile是可以保证可见性,但无法保证原子性,synchronized关键字由于其是加锁机制,肯定是可以保证原子 ...
- synchronized内存可见性理解
一.背景 最近在看<Java并发编程实战>这本书,看到共享变量的可见性,其中说到"加锁的含义不仅仅局限于互斥行为,还包括内存可见性". 我对于内存可见性第一反应是vol ...
- synchronized实现可见性
JMM关于synchronized的两条规定: 1)线程解锁前,必须把共享变量的最新值刷新到主内存中 2)线程加锁时,将清空工作内存中共享变量的值,从而使用共享变量时需要从主内存中重新获取最新的值 ( ...
- java线程-synchronized实现可见性代码
以下是一个普通线程代码: package com.Sychronized; public class SychronizedDemo { //共享变量 private boolean ready=fa ...
- volatile、Synchronized实现变量可见性的原理,volatile使用注意事项
变量不可见的两个原因 Java每个线程工作都有一个工作空间,需要的变量都是从主存中加载进来的.Java内存模型如下(JMM): 线程访问一个共享的变量时,都需要先从主存中加载一个副本到自己的工作内存中 ...
- 1 Java线程的内存可见性
Java内存的可见性 可见性: 一个线程对共享变量的修改,能够及时被其它线程看到 共享变量: 如果一个变量在多个线程的工作内存中都存在副本,那么这个变量就是这几个线程的共享变量 Java内存模型(JM ...
- 细说Java多线程之内存可见性
编程这些实践的知识技能,每一次学习使用可能都会有新的认识 一.细说Java多线程之内存可见性(数据挣用) 1.共享变量在线程间的可见性 共享变量:如果一个 ...
随机推荐
- table-responsive响应式表格,HTML表格自适应,bootstrap2表格自适应
引用bootstrap3 的方法 @media (max-width: 767px) { .table-responsive { width: 100%; margin-bottom: 15px; o ...
- GIS的发展
2016年2月15日,博客园的blog申请成功了,这是我的第一篇随笔,发一个GIS的发展的视频链接 http://buluo.qq.com/p/detail.html?bid=15060&pi ...
- Objective C中数组排序几种情况的总结
总结OC中数组排序3种方法:sortedArrayUsingSelector:;sortedArrayUsingComparator:;sortedArrayUsingDescriptors: 数组排 ...
- C++ mem_fun 和 mem_fun_ref 的用法
假设我们有以下的一个类: 另外有一个包含 class A 对象的数组: vector<A> vec; 如何对每一个类的对象调用成员函数print. 做法1: 利用下标 for(int i= ...
- mac中使用brew安装软件,下载太慢怎么办?
mac中使用brew安装软件,下载太慢怎么办? 本文所说的软件是指较大的软件,如果软件较小,例如软件只有几M,那么使用此方法后,提升会非常小. 了解brew原理: 1: 从网络下载安装包 2: 执行一 ...
- 面向小白的JS笔记 - #Codecademy#学习笔记
前言 最初浏览过<JavaScript秘密花园>,前一段时间读过一点点<JavaScript语言精粹>和一点点<JavaScript高级程序设计>(一点点是指都只是 ...
- Keychain group access
Keychain group access Apr 3, 2010 · 3 minute read · Comments keychain Since iPhone OS 3.0 it has bee ...
- JS控制的动态表格
对应的js: function pccAddSignRow() { //读取最后一行的行号,存放在LearnTRLastIndex文本框中 var pccTRLastIndex = findObj(& ...
- java文件编译及运行
1 配置环境变量 使用鼠标右击“我的电脑”->属性->高级->环境变量 系统变量->新建->变量名:JAVA_HOME 变量值:C:\Program Files (x86 ...
- 深入理解javascript中实现面向对象编程方法
介绍Javascript中面向对象编程思想之前,需要对以下几个概念有了解: 1. 浅拷贝和深拷贝:程序在运行过程中使用的变量有在栈上的变量和在堆上的变量,在对象或者变量的赋值操作过程中,大多数情况先是 ...