volatile

学习笔记1:java多线程机制之线程概念

筅森魡賤 提交于 2020-03-13 00:39:38
由于种种需求,今天开始由浅入深的学习java的多线程机制,而java语言的一大特性点就是内置对多线程的支持。 以下内容出自: http://blog.csdn.net/jiangwei0910410003/article/details/19962627 : 线程的生命周期: 1.新建状态(New):用new语句创建的线程对象处于新建状态,此时它和其它的java对象一样,仅仅在堆中被分配了内存 2.就绪状态(Runnable):当一个线程创建了以后,其他的线程调用了它的start()方法,该线程就进入了就绪状态。处于这个状态的 线程位于可运行池中,等待获得CPU的使用权 3.运行状态(Running): 处于这个状态的线程占用CPU,执行程序的代码 4.阻塞状态(Blocked): 当线程处于阻塞状态时,java虚拟机不会给线程分配CPU,直到线程重新进入就绪状态,它才有机会转到 运行状态。 阻塞状态分为三种情况: 1)、 位于对象等待池中的阻塞状态:当线程运行时,如果执行了某个对象的wait()方法,java虚拟机就回把线程放到这个对象的等待池中 2)、 位于对象锁中的阻塞状态,当线程处于运行状态时,试图获得某个对象的同步锁时,如果该对象的同步锁已经被其他的线程占用,JVM就会把这个线程放到这个对象的琐池中。 3)、 其它的阻塞状态:当前线程执行了sleep()方法

c 的陷阱

你说的曾经没有我的故事 提交于 2020-03-12 22:22:13
c语言算是非常古老了,像瑞士军刀灵活却也很容易伤到自己,即使是多年的老杆子,以致于市面上都有一本经典的C的书叫《C陷阱与缺陷》的书。 这个文章总结下c中常见的陷阱,可能在日常工作或面试题目中遇到。 1. sizeof 陷阱 sizeof 它是一个编译时运算符而非函数,用于判断变量或数据类型的字节大小。 比较常见的用法: int arr[] = { 1, 2, 3 }; for (int i = 0; i < sizeof(arr) / sizeof(int); i++) { printf("%d,", arr[i]); } sizeof(arr)的是整个数组的占字节数大小,除int占字节大小就是整个数组的大小了,但是如果不小心这样用了: void clear(char array[]) { int i; for (i = 0; i < sizeof(array) / sizeof(array[0]); i++) { array[i] = 0x00; } } int main(void) { char arr[20]; clear(arr); } 问题: 这段代码的问题,在于clear中传递的是指针,这时候sizeof(char*) 一般为4,sizeof(array[0]),造成了结果是只对数组的前四个变量赋值为0,其他的没有赋值! 2. 小心无符号类型 先看段代码:

深入理解Java内存模型(四)——volatile

陌路散爱 提交于 2020-03-12 17:05:20
作者 程晓明 发布于 2013年2月5日 领域 架构 & 设计 , 语言 & 开发 主题 Java , 多线程 , 并发 , 内存模型 , 专栏 volatile的特性 当我们声明共享变量为volatile后,对这个变量的读/写将会很特别。理解volatile特性的一个好方法是:把对volatile变量的单个读/写,看成是使用同一个监视器锁对这些单个读/写操作做了同步。下面我们通过具体的示例来说明,请看下面的示例代码: class VolatileFeaturesExample { volatile long vl = 0L; //使用volatile声明64位的long型变量 public void set(long l) { vl = l; //单个volatile变量的写 } public void getAndIncrement () { vl++; //复合(多个)volatile变量的读/写 } public long get() { return vl; //单个volatile变量的读 } } 假设有多个线程分别调用上面程序的三个方法,这个程序在语意上和下面程序等价: class VolatileFeaturesExample { long vl = 0L; // 64位的long型普通变量 public synchronized void set(long l)

java volatile详解(转)

随声附和 提交于 2020-03-12 17:05:04
volatile的特性 当我们声明共享变量为volatile后,对这个变量的读/写将会很特别。理解volatile特性的一个好方法是:把对volatile变量的单个读/写,看成是使用同一个监视器锁对这些单个读/写操作做了同步。下面我们通过具体的示例来说明,请看下面的示例代码: class VolatileFeaturesExample { volatile long vl = 0L; //使用volatile声明64位的long型变量 public void set(long l) { vl = l; //单个volatile变量的写 } public void getAndIncrement () { vl++; //复合(多个)volatile变量的读/写 } public long get() { return vl; //单个volatile变量的读 } } 假设有多个线程分别调用上面程序的三个方法,这个程序在语意上和下面程序等价: class VolatileFeaturesExample { long vl = 0L; // 64位的long型普通变量 public synchronized void set(long l) { //对单个的普通 变量的写用同一个监视器同步 vl = l; } public void getAndIncrement () { /

何为安全发布,又何为安全初始化?

你。 提交于 2020-03-12 08:40:54
前言 很多时候我们需要跨线程共享对象,若存在并发我们必须以线程安全的方式共享对象,此时将涉及到我们如何安全初始化对象从而进行安全发布,本节我们将来讨论安全初始化、安全发布,文中若有错误之处,还望批评指正。 安全发布 按照正常叙述逻辑来讲,我们应该首先讨论如何安全初始化,然后再进行安全发布分析,在这里呢,我们采取倒叙的方式,先通过非安全发布的方式讨论所出现的问题,然后最后给出如何进行安全初始化,如下,我们以单例模式为例。 public class SynchronizedCLFactory { private Singleton instance; public Singleton get() { synchronized (this) { if (instance == null) { instance = new Singleton(); } return instance; } } } public class Singleton { } 如上提供了用于获取Singleton实例的公共方法,我们通过同步关键字保持线程安全,无论有多少个线程在请求一个Singleton,也不管当前状态如何,所有线程都将获得相同的Singleton实例,Singleton初始化在第一次请求Singleton时发生,而不是在初始化Singleton类时发生,至于是否惰性初始化并不是我们关注的重点

volatile关键字用法

爷,独闯天下 提交于 2020-03-12 07:19:47
JAVA提供一种稍弱的同步机制,即volatile变量,用来确保将线程变量同步到其他线程,可以将volatile看做一个轻量级的锁,但是又与锁有些不同: ** 对于多线程,不是一种互斥关系 不能保证变量状态的“原子型操作” 原子性操作的解释: 例如i++;这个操作,它不是一个原子性操作,在实际执行是需要三步操作“读-改-写” int temp = i; temp = temp + 1 ; i = temp; 下面是volatile的实例代码: /** * @author zhengzheng046 */ public class TestVolatile { public static void main ( String [ ] args ) { ThreadDemo threadDemo = new ThreadDemo ( ) ; new Thread ( threadDemo ) . start ( ) ; while ( true ) { if ( threadDemo . isFlag ( ) ) { System . out . println ( "flag为true,主线程循环结束----------------" ) ; break ; } } } } class ThreadDemo implements Runnable { private boolean

Java多线程系列--利用自旋原理来无锁实现“只创建一次”的场景

自古美人都是妖i 提交于 2020-03-11 10:09:21
相信看过之前几篇自旋锁实现的同学对设计一个自旋锁会有一定的感觉,有几个实现的要点很实用: 1. 使用AtomicBoolean原子变量的getAndSet(true)方法来实现并发情况下,找到第一个成功执行方法的线程。这个技巧经常使用,在并发编程中经常会遇到这种需求 2.经常会使用volatile boolean类型的变量在多个线程之间同步状态,需要注意的是,对volatile变量的修改只具有可见性,不具有原子性(比如++操作)。 3. 使用一个AtomicReference原子变量的getAndSet方法来创建一个虚拟的链表结构,原理也是CAS操作,在队列锁中经常使用 这篇结合一个实例来说说如何灵活地利用这些技巧实现无锁的能力。 在实际开发中会经常遇到“只创建一次”的场景,这里说的“只创建一次”不是说单实例模式。单实例模式也是解决只创建一次的问题,关于单实例模式有很多技巧来实现高并发情况下只创建一个对象的问题,这里不讨论。 单实例模式解决的问题是所有线程都公用一个静态的引用,可以用volatile变量来标示这个静态引用,从而在所有线程之间共享这个静态引用的状态是否已经改变。 这里说的“只创建一次”的场景是这个需要创建一次的对象不是直接被全局的引用所引用,而是间接地被引用。经常有这种情况,全局维护一个并发的ConcurrentMap, Map的每个Key对应一个对象

MDK编译优化笔记

北战南征 提交于 2020-03-11 06:00:37
在一次使用MDk的编译优化等级比较高的时候发现编译不优化时功能正常,开了优化等级0 2就出现异常,调试中看了很多博客总结一下。 一个变量,如果你的主程序要用到,同时中断还要用到,要加volatile修饰。告诉编译器这个变量是可能随时发生变化的,使得编译器编译程序的时候,每次都从RAM里面读取数据,而不是使用之前缓存到寄存器里面的值。 对于多任务的程序,如果一个公共变量被多个任务用到也要加volatile修饰。 同时变量定义的时候用了关键字volatile修饰,但是在其他文件引用时不加volatile变量修饰一样会被编译器优化掉。现则反过来想想,原因还是很简单的,MDK编译多个文件时是分别编译,最后再用链接器链接,当编译的时候一个模块引用另外一个模块的变量,完全是靠的变量声明,如果声明都不加volatile,那么引用的模块肯定会把变量当成普通变量的,再反推一下,如果原变量没有加volatile,但是声明的时候加了volatile,是不是引用的模块会将这个变量当成volatile型变量呢   C编译器是以每个C文件作为基本编译单元的,称为模块,被编译为obj;而模块之间的函数或变量访问都是通过标号来实现的,标号本身没有任何属性,只是提供给链接器使用的一个符号名称而已,标号的属性完全就靠调用的地方的原型声明来决定的!因此,你在一个.C模块中定义为volatile,仅仅是在

你必须要知道的锁原理、锁优化、CAS、AQS

孤者浪人 提交于 2020-03-10 16:23:18
1、为什么要用锁? 锁-是为了解决并发操作引起的脏读、数据不一致的问题。 2、锁实现的基本原理 2.1、volatile Java编程语言允许线程访问共享变量, 为了确保共享变量能被准确和一致地更新,线程应该确保通过排他锁单独获得这个变量。Java语言提供了volatile,在某些情况下比锁要更加方便。 volatile在多处理器开发中保证了共享变量的“ 可见性”。可见性的意思是当一个线程修改一个共享变量时,另外一个线程能读到这个修改的值。 结论:如果volatile变量修饰符使用恰当的话,它比synchronized的使用和执行成本更低,因为它不会引起线程上下文的切换和调度。 2.2、synchronized synchronized通过锁机制实现同步。 先来看下利用synchronized实现同步的基础:Java中的每一个对象都可以作为锁。 具体表现为以下3种形式。 对于普通同步方法,锁是当前实例对象。 对于静态同步方法,锁是当前类的Class对象。 对于同步方法块,锁是Synchonized括号里配置的对象。 当一个线程试图访问同步代码块时,它首先必须得到锁,退出或抛出异常时必须释放锁。 2.2.1 synchronized实现原理 synchronized是基于Monitor来实现同步的。 Monitor从两个方面来支持线程之间的同步: 互斥执行 协作 1、Java

JAVA并发编程的学习之路

让人想犯罪 __ 提交于 2020-03-08 12:57:07
一Java内存模型 1 Java内存模型(JMM):为了屏蔽各种硬件和操作系统的内存访问差异, 以实现java程序在任何平台下有相同的并发效果,Java虚拟机规范中定义了java内存模型。 它规范了java虚拟机与计算机内存是如何协调工作的 ,规定了一个线程何时可以看到被其它线程修改过的共享变量的值,以及如何在必须时同步的访问共享变量。 2 同步8种操作:lock、unlock、read、load、use、assign、store、write lock:作用与主内存的变量,把变量设成一个线程独占的状态 unlock:作用与主内存的变量,把锁定的线程释放 read:作用与主内存的变量,把一个变量的值,输送到工作内存中 load:作用与工作内存的变量,把read从主内存读入的变量放入工作内存的副本中 use:作用与工作内存的变量,把工作内存中变量的值传给执行引擎,每当虚拟机遇到一个需要用到这个值的字节码指令时执行的操作 assign(赋值):作用与工作内存的变量, 把一个从执行引擎获取到的值赋给工作变量,每当虚拟机遇到一个需要赋值的字节码指令时执行的操作 store:作用与工作内存的变量,把工作内存中的变量值传入到主内存 write:作用与主内存的变量,把store传入过来的变量存入主内存 二线程安全性 1 线程安全性:当多个线程访问某个类时,不管这些线程采用何种调度方式