文档章节

JAVA并发编程学习:共享对象

HenrySun
 HenrySun
发布于 2016/08/26 20:21
字数 1167
阅读 111
收藏 5

可见性

  在一个单线程程序中,如果向一个变量先写入值,然后在没有写干涉的情况下读取这个变量,会得到相同的返回值。但是当读和写发生在不同的线程中时,就不能保证读线程及时地读取其他线程写入的值。在JAVA中所有实例域、静态域和数组元素存储在堆内存中,堆内存在线程之间共享,局部变量,方法定义参数和异常处理器参数不会在线程之间共享,它们不会有内存可见性问题,也不受内存模型的影响。为了确保跨线程写入的内存可见性,必须使用同步机制

  下例是主线程和读线程两个线程访问共享变量ready和number。主线程启动读线程,然后把number的值设为42,ready的值赋为true。读线程进行循环,直到发现ready的值变为true,然后打印出number的值。虽然看起来会输出42,但事实上,它很有可能打印出0,或者根本不会终止。这是因为它没有使用恰当的同步机制,没能保证主线程写入ready和number的值对读线程是可见的

package com.henrysun.javaSE.bfbc;

/**
 * 在没有同步的情况下共享变量(不要这样做)
 * 重排序现象
 * @author Sam Flynn
 *
 */
public class GongXiangBianLiangReordering {

	private static boolean ready;
	private static int	number;
	
	private static class ReaderThread extends Thread
	{
		public void run()
		{
			while(!ready)
			{
				Thread.yield();
			}
			System.out.println(number);
		}
	}
	
	/**
	 * @param args
	 */
	public static void main(String[] args) {
	   new ReaderThread().start();
	   number=42;
	   ready=true;
	}

}

重排序现象

  上面的例子中,可能会打印0,因为早在对number赋值之前,主线程就已经写入ready并使之对读线程可见,这叫做“重排序(reordering)”现象

  这里处理器A和处理器B可以同时把共享变量写入自己的写缓冲区(A1,B1),然后从内存中读取另一个共享变量(A2,B2),最后才把自己写缓存区中保存的脏数据刷新到内存中(A3,B3)。当以这种时序执行时,程序就可以得到x = y = 0的结果

锁和可见性

  锁不仅仅是关于同步互斥的,也是关于内存可见的。当线程A执行一个同步块时,线程B也随后进入了被同一个锁监视的同步块中,这时可以保证,在锁释放之前对A的可见的变量的值,B获得锁之后同样是可见的。换句话说,当B执行到A相同的锁监视的同步块时,A在同步块之中或之前所做的每件事,对B都是可见的。为了保证所有线程都能够看到共享的,可变变量的最新值,读取和写入线程必须使用公共的锁进行同步

Volatile变量

  当一个域声明为volatile类型后,编译器与运行时会监视这个变量:它是共享的,而且对它的操作不会与其他的内存操作一起被重排序。volatile变量不会缓存在寄存器或者缓存在其他对处理器隐藏的地方。所以,读一个volatile类型的变量时,总会返回由某一线程写入的最新值

  但是volatile变量的操作不会加锁,也就不会引起执行线程的阻塞,所以它只是轻量级的同步机制,正确使用volatile变量的方式包括:用于确保它们所引用的对象状态的可见性,或者用于标识重要的生命周期事件(比如初始化或关闭)的发生,即通常被当作标识完成、中断、状态的标记使用

  尽管volatile也可以用来标识其他类型的状态信息,但是决定这样做之前请格外小心。比如,volatile的语义不足以使自增操作(count++)原子化,除非你能保证只有一个线程对变量执行写操作。加锁可以保证可见性与原子性,而volatile变量只能保证可见性

  只有满足了下面的标准,才能使用volatile变量

  • 写入变量时并不依赖变量的当前值;或者能够确保只有单一的线程修改变量的值
  • 变量不需要与其他的状态变量共同参与不变约束
  • 而且,访问变量时,没有其他的原因需要加锁

ThreadLocal

  线程本地变量,详见Java多线程学习:深入剖析ThreadLocal

© 著作权归作者所有

HenrySun
粉丝 89
博文 121
码字总数 41919
作品 0
深圳
高级程序员
私信 提问
JVM内存结构 VS Java内存模型 VS Java对象模型

Java作为一种面向对象的,跨平台语言,其对象、内存等一直是比较难的知识点。而且很多概念的名称看起来又那么相似,很多人会傻傻分不清楚。比如本文我们要讨论的JVM内存结构、Java内存模型和...

Java架构
2018/07/11
0
0
基于JVM原理、JMM模型和CPU缓存模型深入理解Java并发编程

许多以Java多线程开发为主题的技术书籍,都会把对Java虚拟机和Java内存模型的讲解,作为讲授Java并发编程开发的主要内容,有的还深入到计算机系统的内存、CPU、缓存等予以说明。实际上,在实...

leoliu168
2018/11/08
0
0
基于JVM原理JMM模型和CPU缓存模型深入理解Java并发编程

许多以Java多线程开发为主题的技术书籍,都会把对Java虚拟机和Java内存模型的讲解,作为讲授Java并发编程开发的主要内容,有的还深入到计算机系统的内存、CPU、缓存等予以说明。实际上,在实...

Java高级技术
2018/11/21
0
0
深入理解Java中的不可变对象

深入理解Java中的不可变对象 不可变对象想必大部分朋友都不陌生,大家在平时写代码的过程中100%会使用到不可变对象,比如最常见的String对象、包装器对象等,那么到底为何Java语言要这么设计...

java菜分享
04/14
0
0
Java多线程学习(四)等待/通知(wait/notify)机制

系列文章传送门: Java多线程学习(一)Java多线程入门 Java多线程学习(二)synchronized关键字(1) java多线程学习(二)synchronized关键字(2) Java多线程学习(三)volatile关键字 Ja...

一只蜗牛呀
2018/04/16
0
0

没有更多内容

加载失败,请刷新页面

加载更多

利用mybatis generator生成实体类、Mapper接口以及对应的XML文件

项目中通常会遇到数据的持久化,如果是采用mybatis的orm,就会涉及到生成xml的问题,刚好mybatis官网提供了这么个插件MyBatis Generator,效果简直是棒呆。 1. 首先需要在build.gradle文件中...

啊哈关关
今天
2
0
SpringSocial相关的知识点

使用SprigSocial开发第三方登录 核心类 ServiceProvider(AbstractOauth2ServiceProvider):主要负责实现server提供商(例如QQ,微信等共有的东西),默认实现类是AbstractOauth2ServiceProvider...

chendom
今天
2
0
Java并发之AQS详解

一、概述   谈到并发,不得不谈ReentrantLock;而谈到ReentrantLock,不得不谈AbstractQueuedSynchronizer(AQS)!   类如其名,抽象的队列式的同步器,AQS定义了一套多线程访问共享资源...

群星纪元
昨天
2
0
Fabric-sdk-java最新教程

Fabric Java SDK是Fabric区块链官方提供的用于Java应用开发的SDK,全称为Fabric-sdk-java,网上可用资料不多,本文列出了精心整理的针对Fabric Java SDK的最新精选教程。 如果希望快速掌握F...

汇智网教程
昨天
3
0
react 子组件监听props 变化

componentWillReceiveProps //已经被废弃 getDerivedStateFromProps// 推荐使用//如果条件不存在必须要返回null static getDerivedStateFromProps(props, current_stat...

一箭落旄头
昨天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部