原子操作:不可被中断的操作。要么全执行,要么全不执行。

现代CPU读取内存,通过读取缓存再写入主存。先去主存读--->写入缓存---->运行线程--->写入缓存---->写入主存

多cpu时会出现缓存一致性和总线锁的问题。

只有简单的读取,赋值操作,即一步完成的操作才是原子操作。

volatile,synchronized,lock 能保证可见性,

volatile保证修改的值立即更新到主存,synchronized和lock保证同一时刻只有一个线程操作变量,在锁被释放前会将新值写入内存。

线程的有序性:

java内存模型具备一些先天的有序性,即happensbefore(先行发生)原则:

1,程序次序规则,一个线程内,按照代码书写顺序执行

2,锁定规则,一个解锁操作ounlock先行发生于后面对同一个锁的lock操作

3,volatile变量规则,对一个变量的写操作先行发生于后面对这个变量的读操作

4,传递规则,A先发生于B,B先发生于C,则A先发生于C

5,线程启动规则,Thread对象的start()方法先行发生于此线程的每一个操作

6,线程中断规则,对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生,即中断的发生先于中断被检测到

7,线程终结规则,线程中所有的操作都先行发生于线程的中止检测,可以通过Thread.join()方法结束,Thread.isAlive()的返回值手段检测到线程已经终止

8,对象终结规则,一个对象的初始化完成先行发生于他的finalize()方法的开始

1·8·来源于《深入理解java虚拟机》

在单个线程中,虚拟机有可能对指令进行重排序。虽然进行重排序,但是最终执行的结果与程序顺序执行的结果是一致的。它只会对不存在数据依赖性的指令进行重排序。

在多线程中则能保证执行顺序。

一旦一个共享变量,比如类的成员变量,类的静态成员变量,被volatile修饰之后,那么它就具备了两层语义:

1,保证了不同线程对这个变量进行操作时是可见的,即一个线程修改了某个变量的值,这个新值对其他线程来说是立即可见的。

2,禁止进行指令重排序。

但是volatile不保证操作的原子性,比如对自增操作等不能保证原子性。

对自增操作,可以用synchronized和lock保证操作的原子性。也可以用AtomicInteger操作来进行自增。原因是atomic是利用CAS的原理实现原子操作。CAS利用处理器提供的CMPXCHG指令实现,处理器执行CMPXCHG指令是一个原子操作。

long或double的赋值操作不是原子操作,比如在32位机上对long和double的读写将会分成两步进行。用volatile修饰时,long和double的读写将会变成原子的。

线程局部(本地)变量是指局限于线程内部的变量,不与其他线程共享。

java提供ThreadLocal类来支持线程局部变量,它好似一种实现线程安全的方式。

在web服务器上使用线程局部变量的时候,它的生命周期比任何应用程序的变量的生命周期都要长,所以如果使用完毕后而不释放,救会有内存泄露的风险。

sleep()只是短暂休眠线程,并不会释放锁。

wait()指等待某条件。只有释放掉锁,其他等待的线程才能在满足条件时获取到该锁,所以wait()又叫条件等待。

单例的目的是为了保证运行时Singleton类只有一个实例,因为instance = new Singleton()的性能开销较大。最常用的地方比如获取数据库连接,spring中创建beanFactory等。

单例模式的七种写法:

1,懒汉式,线程不安全,在多线程下不能正常工作:

public class Singleton{

private static Singleton instance;

private Singleton(){};

public static Singleton getInstance(){

if(instance == null){

instance = new Singleton ();

}

return instance;

}

}

2,懒汉式,线程安全,在多线程下也正常工作,但是效率低下,99%的情况不需要同步

/***lazy **thread safety*/
public class Singleton{
private static Singleton instance;
private Singleton(){};
public static synchronized Singleton getInstance(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
}

3,饿汉式,基于classloader机制避免了线程同步,但是没有lazy loading的效果,在类装载时就实例化

public class Singleton{
private static Singleton instance = new Singleton();
private Singleton(){};
public static Singleton getInstance(){
return instance;
}
}

4,饿汉式的变种,也是在类加载时即实例化,没有实现懒加载

public class Singleton{
private static Singleton instance = null;
static{
instance = new Singleton();
}
private Singleton(){};
public static Singleton getInstance(){
return instance;
}
}

5,静态内部类,这是一种推荐的写法,懒加载且单线程,只有在显式调用getInstance()的时候SingletonHolder类才被装载

public class Singleton{
private static class SingletonHolder{
private static final Singleton INSTANCE = new Singleton();
}
private Singleton(){};
public static Singleton getInstance(){
return SingletonHolder.INSTANCE;
}
}

6,枚举,effective java推荐的写法,线程安全的单例模式最推荐的写法

避免了多线程同步,防止反序列化重新创建新的对象

因为JVM类初始化是线程安全的,所以可以采用枚举类实现一个线程安全的单例模式

public enum Singleton{

INSTANCE;

public void whateverMethod(){

}

}

7,双重校验锁

public class Singleton{
private volatile static Singleton instance;
private Singleton(){};
public static Singleton getInstance(){
if(instance == null){
synchronized(Singleton.class){
if(instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}

双重校验锁是不安全的,java内存模型允许"无序写入",无序写入将会导致二次检查失败。JDK5以后可以使用双重校验锁,但是不推荐。

任何时候都不应该使用双重校验锁,因为无法保证它能在任何JVM上都能顺利运行。

之所以会有双重校验锁,是因为以下代码:

if(instance == null ){//两个线程在初始化判断的时候同时进入

synchronized(Singleton.class){//线程2在此时被锁定

instace = new Singleton();

}//线程1 执行实例化完毕唤醒线程2,线程2 将不会经过检查,而是直接再次执行实例化动作,造成出错。因为检查这一步已经过了

retunr instance;

}

如果一个单例类由多个不同的类装载器装载,比如有连个servlet访问同一个单例类,则这两个servlet会生成各自的实例。

如果单例类Singleton实现了serializedble接口,那么这个类的实例就可能被序列化和复原。不管怎么样如果你序列化一个单例类的对象,接下来复原那个对象,你就会有多个单例类的实例。

原子操作和volatile关键字的更多相关文章

  1. java并发:线程同步机制之Volatile关键字&原子操作Atomic

    volatile关键字 volatile是一个特殊的修饰符,只有成员变量才能使用它,与Synchronized及ReentrantLock等提供的互斥相比,Synchronized保证了Synchro ...

  2. java IO操作和计算操作:工作内存和主内存 volatile关键字作用;原子操作对象AtomicInteger ....

    应该停止但无法停止的计算线程 如下线程示例,线程实例中while循环中的条件,在主线程中通过调用实例方法更新后,while循环并没有更新判断变量是否还成立.而是陷入了while(true)死循环. i ...

  3. Java并发编程:volatile关键字解析

    Java并发编程:volatile关键字解析 volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果.在 ...

  4. 【转】Java并发编程:volatile关键字解析

    转自:http://www.importnew.com/18126.html#comment-487304 volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备 ...

  5. zz剖析为什么在多核多线程程序中要慎用volatile关键字?

    [摘要]编译器保证volatile自己的读写有序,但由于optimization和多线程可以和非volatile读写interleave,也就是不原子,也就是没有用.C++11 supposed会支持 ...

  6. Java多线程6:synchronized锁定类方法、volatile关键字及其他

    同步静态方法 synchronized还可以应用在静态方法上,如果这么写,则代表的是对当前.java文件对应的Class类加锁.看一下例子,注意一下printC()并不是一个静态方法: public ...

  7. 内存管理_深入剖析volatile关键字

    四.深入剖析volatile关键字 在前面讲述了很多东西,其实都是为讲述volatile关键字作铺垫,那么接下来我们就进入主题. 1.volatile关键字的两层语义 一旦一个共享变量(类的成员变量. ...

  8. (转)Java并发编程:volatile关键字解析

    转:http://www.cnblogs.com/dolphin0520/p/3920373.html Java并发编程:volatile关键字解析 volatile这个关键字可能很多朋友都听说过,或 ...

  9. Java Volatile关键字

    在当前的Java内存模型下,线程可以把变量保存在本地内存(比如机器的寄存器)中,而不是直接在主存中进行读写. 这就可能造成一个线程在主存中修改了一个变量的值,而另外一个线程还继续使用它在寄存器中的变量 ...

随机推荐

  1. SharePoint 2010 究竟需要占用多少服务器资源?

    SharePoint 安装目录(即SharePoint Root)大约 300M 磁盘空间. SharePoint Config 数据库,60M. Admin Center 数据库,100M. 默认安 ...

  2. 关于VisualStudio2010发布项目问题

    VisualStudio2010速度还是很给力的,VS2015打开机器就双100%了:VS2010机器上跑起来还是很好用的. 今天编译一个MVC3.0项目,发布时候出现诡异现象:Content文件夹里 ...

  3. Python基础学习之字符串(1)

    字符串 由字符组成的序列,即字符串. 1.基本字符串操作 所有标准的序列操作(索引.切片.乘法.判断成员资格.求长度.取最小值和最大值)对字符串同样适用: >>> website=' ...

  4. Leetcode 78. Subsets (backtracking) 90 subset

    using prev class Solution { List<List<Integer>> res = new ArrayList<List<Integer&g ...

  5. 使用extentreports美化testng报告2,增加监听

    有兴趣研究了extentreports报告美化插件,但是因为发现插件有很多内容不能自定义,所以放弃了这个插件,我扩充了官方代码的demo,在testng中增加了监听,并打印了一些测试用例,现在我把两个 ...

  6. LCT入门

    前言 \(LCT\),真的是一个无比神奇的数据结构. 它可以动态维护链信息.连通性.边权.子树信息等各种神奇的东西. 而且,它其实并不难理解. 就算理解不了,它简短的代码也很好背. \(LCT\)与实 ...

  7. 画X,模拟水题

    题目链接:http://codeforces.com/contest/404/problem/A #include <stdio.h> #include <string.h> ...

  8. P1151 子数整数

    题目描述 对于一个五位数a_1a_2a_3a_4a_5a1​a2​a3​a4​a5​,可将其拆分为三个子数: sub_1=a_1a_2a_3sub1​=a1​a2​a3​ sub_2=a_2a_3a_ ...

  9. Django Reverse for 'artic_post' with arguments '()' and keyword arguments '{}' not found. 0 pattern(s) tried: []

    Reverse for 'home' with arguments '()' and keyword arguments '{}' not found. 0 pattern(s) tried: [] ...

  10. java的四个元注解 @Retention @Target @Document @Inherited

    1.  @Retention  :注解的保留位置 @Retention(RetentionPolicy.SOURCE)  //注解仅存在于源码中,在class字节码文件中不包含 @Retention( ...