参考文章:https://blog.csdn.net/huyiju/article/details/97126274
一、voliate相关

1:java内存模型

1.1:计算机的内存模型
在计算机的内存模型中cpu和内存之间的速度存在数量级所以引入了高速缓存,告诉缓存会导致到底以哪个处理器的缓存为主,同步到主内存,这个时候有有了缓存一致性协议,来保证缓存一致性。


指令重排:例如一下五行代码,前四行的在计算机cpu的执行顺序不一定是12345,也可以是13245或者34125,但是第五步的顺序不会变,这种指令重排不会影响最后的计算结果。

          int a=1;a++;int b=5;b++;int c=a+b;

1.2:java内存模型

java的内存模型屏蔽掉了计算机硬件和操作系统的差异,但是没有限制处理器使用缓存和主内存进行交互,也没有限制编译器在执行过程中的指令重排这类优化措施。

2:Voliate关键字
voliate关键字有两个作用(可见性和禁止指令重排)

1:可见性:保证在多个线程的情况下,线程一把int a的值修改为5的时候,其他线程也能立即知道int a=5,实现的方法是线程1把int a=5,会把a=5的是立马通过缓存同步到主内存,然后其他线程使用a之前会从主内存刷新一次,得到被线程1修改的值为5.

2:有序性:有序性的意思的在本线程内观察,所有操作都是有序的(线程内是串行的),但是在另一个线程观察本线程,所有操作都是无序的(主要是指指令重排现象和工作内存与主内存同步)。voliate和synchronize两个关键字来保证线程操作之间的有序性。

2.1:voliate不能保证线程安全(可见性分析)
预期结果:10个线程同时执行,每一个此线程都把i累加到1000.最后的结果应该是10000.

实际结果:多次运行,大部分结果都不足10000

结论分析:i++,不是原子性操作,线程1把i的值赋值的10,这个时候后线程2根据可见性也得到了10,但是线程1接着执行累加把i的值赋值到250,这个时候线程2依然拿到的值是10是过期数据,入栈++后的值为11,把11同步到了主内存,触发了线程1从主内存同步的得到值为11,这个时候会导致线程一的结果错误。

public class VoliteTest {//voliate关键字保证了此变量在各个线程中是一致的public static volatile int id=1;public static void main(String[] args) throws InterruptedException {// TODO Auto-generated method stubThread[] ths=new Thread[10];for(int i=0;i<10;i++) {//10个线程同时执行ths[i]=new Thread(new Runnable() {@Overridepublic void run() {// TODO Auto-generated method stubadd();}});ths[i].start();}//累加线程执行完毕while (Thread.activeCount()>1) {Thread.yield();}System.out.println("========================");System.out.println("ID的值是:"+id);}//该方法可以通过加锁实现线程安全public  static void add() {for(int i = 0;i<1000;i++) {//id++不是原子性的//第一步:假如线程1同步id=5,这个时候要++,其他线程切换了进来//第二部:其他比如线程2同步id=5,执行了很多操作,id=100了//第三部:线程1执行++,得到了id=6,这个时候的id为5已经是过期数据了,//第四部:线程1将结果6同步到内存共享,其他的线程得到id=6.会导致最后的值不等于10001id++;}}}

2.2:voliate禁止指令重排
voliate保证cpu能够保证在这个关键字之前和之后的代码不会指令重排,保证按照书写顺序执行代码。

之所以能实现指令重排是因为voliate的可见性决定的,这个关键字保证了从缓存到主内存之间的同步,就像内存之间的一道屏障,保证了之前和之后的代码无法越过这个 内存栅栏。

单例代码案例:保证线程安全和只有一个实例

public class Danli {private volatile static Danli danli;//私有构造,防止通过外部new创建对象private Danli() {}//懒汉模式  需要的时候get//(方法加锁导致多线程效率低)public static synchronized Danli getDanli() {if(danli==null) {//在此处判断加锁,防止线程1判断为空后,线程二创建了实例//在加锁方法之内再次判断一次synchronized (Danli.class) {if(danli==null) {//再次判断danli=new Danli();//内存屏障,保证写完之后其他线程读取//1:在工作内存创建,(store存储)到主内存//在此之间可能有其他线程插入//2:主内存的danli(write写入)//这是一个内存栅栏}}}return danli;}}

二、synchronize关键字

2.1:说一下对synchronize关键字的理解
synchronize关键字解决了多线程的资源同步性,该关键字保证了在多线程的条件下,同时是有一个线程能够获取到资源。

在jdk的早起版本中,这个关键字是重量级锁,这个关键字在编译之后,在同步块的前后会形成monitorenter和monitorexit(监视器进入和退出,通过获取对象锁计数器加一减一来实现锁机制)两个节码指令,其他线程在竞争的时候会挂起,效率低下,但是随着jdk的发展,通过对synchronize底层的发展,不必每次线程都挂起。来大大提升了效率

比如采用偏向锁、轻量级锁、锁粗化、锁自旋、锁自旋、锁消除等手段来提升效率

2.2:synchronize在用项目中用到了吗?
2.2.1:synchronize用法
1:用来修饰静态方法(给类加了锁,无论new多少个对象,都会产生竞争,线程1new的对象获取普通加锁方法和线程2获取类的静态加锁方法不会产生竞争)

2:用来修饰静态代码块(也是给类加了锁)

3:用来修饰普通方法(锁给了对象,只用new的同一对象才有竞争)

2.2.2:项目中的使用(懒汉单例模式)

package com.thit.connpool;public class LazySimple {//voliate修饰,禁止指令重排private static volatile LazySimple lazySimple;//私有构造防止new创建对象private LazySimple() {}//静态方法外部得到实例public static LazySimple getDanli() {//首先判断是否为空if (lazySimple==null) {synchronized (LazySimple.class) {//再次判断是否为空if(lazySimple==null) {//new 对象非原子性操作//1:分配内存空间//2:初始化值(构造器)//3:将对象指向内存地址lazySimple=new LazySimple();}}}return lazySimple;}
}

代码分析:

1:其中 volatile修饰lazySimple;是为了防止指令重排,其中lazySimple=new LazySimple();这段代码不是原子性操作,实际分为3步

                //1:分配内存空间//2:初始化值//3:将引用指向内存地址lazySimple=new LazySimple();

由于jvm有指令重排的优化,所以代码执行顺序可能是1>3>2,当线程1执行1>3的时候没有执行到2初始化赋值的时候,线程2进入执行,这个时候判断到lazySimplenull,会在创造一个对象,就不是单例了。加了voliate关键字修饰,会因为可见性而防止指令重排,因为其他的线程想要判断lazySimplenull的时候,会在1>2>3执行完成,在线程1修改lazySimple的时候,没写入之前内存像是有屏障一般。这边形成了指令重排无法越过的内存屏障。

三、说说synchronize关键字和voliate关键字
1:voliate修饰变量多线程可见性但是没有原子性,synchronize修饰方法能保证可见性和原子性。

2:voliate的效率更高一点,线程不会阻塞,但是synchronize线程会阻塞

3:voliate用来解决变量的多线程可见性,但是synchronize用来解决多线程资源访问问题

四、lock接口
4.1:为什么需要Lock接口?

我们知道锁是来控制多线程并发访问资源的竞争,在Lock接口出现之前我们使用synchronize关键字来实现锁功能,但是synchronize获取锁是隐式的,我们无法控制锁的获取,释放中断的可操作性性,由于synchronize获取锁固话,所以创建了Lock接口来实现更领过的锁。

Lock和synchronize都是重入锁

1:尝试非中断的获取锁,

2:可以实现中断,与synchronize关键字不同,当获取锁的线程能够响应中断,中断的时候,异常内抛出,释放锁

3:能指定时间获取锁,在指定时间内无法获取锁的时候返回

4.2:代码实现

Lock lock=new ReentrantLock();lock.lock();//获取锁try {} catch (Exception e) {e.printStackTrace();}finally {lock.unlock();//finally修饰,异常处理,一定要释放锁}

原文链接:https://blog.csdn.net/huyiju/article/details/97646152

voliate Synchronized Lock相关推荐

  1. 6,synchronized, lock 区别

    参考文档 http://zzhonghe.iteye.com/blog/826162 http://houlinyan.iteye.com/blog/1112535 1,ReentrantLock 拥 ...

  2. 【Java线程】线程同步—synchronized Lock

    同步的实现当然是采用锁了,java中使用锁的两个基本工具是 synchronized 和 Lock. ========================================== synchr ...

  3. Synchronized Lock 锁 同步

    如果锁的是类对象的话,尽管new多个实例对象,但他们仍然是属于同一个类依然会被锁住,即线程之间保证同步关系. 字符串作为锁对象的参考 一.synchronized的性质 1.可重入性 官方解释:指的是 ...

  4. Java多线程----java 对象锁(synchronized/lock)

    在并发环境下,解决共享资源冲突问题时,可以考虑使用锁机制. 1. 对象锁 所有对象都自动含有单一的锁.      JVM负责跟踪对象被加锁的次数.如果一个对象被解锁,其计数变为0.在任务(线程)第一次 ...

  5. java voliate_Java之voliate, synchronized, AtomicInteger使用

    1: voliate 用在多线程,同步变量. 线程为了提高效率,将成员变量(如A)某拷贝了一份(如B),线程中对A的访问其实访问的是B.只在某些动作时才进行A和B的同步.因此存在A和B不一致的情况.v ...

  6. synchronized与Lock的区别与使用

    原文链接 https://blog.csdn.net/u012403290/article/details/64910926 ###引言: 昨天在学习别人分享的面试经验时,看到Lock的使用.想起自己 ...

  7. java同步锁售票_Java基础学习笔记: 多线程,线程池,同步锁(Lock,synchronized )(Thread类,ExecutorService ,Future类)(卖火车票案例)...

    学习多线程之前,我们先要了解几个关于多线程有关的概念. 进程:进程指正在运行的程序.确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能. 线程:线程是 ...

  8. 【Java并发系列04】线程锁synchronized和Lock和volatile和Condition

    一.前言 多线程怎么防止竞争资源,即防止对同一资源进行并发操作,那就是使用加锁机制.这是Java并发编程中必须要理解的一个知识点.其实使用起来还是比较简单,但是一定要理解. 有几个概念一定要牢记: 加 ...

  9. Lock和Synchronized区别

    https://blog.csdn.net/zhangcanyan/article/details/80284586 一.synchronized和lock的用法区别 synchronized:在需要 ...

最新文章

  1. 《Redis设计与实现》之第四章:字典
  2. SET QUOTED_IDENTIFIER ON
  3. mysql8 允许外网访问
  4. redis 原码安装
  5. 一个民工的数字化生活
  6. py程序员写代码的习惯养成 防止想到什么写什么
  7. 记一次Jenkins 打包异常 ERROR: Exception when publishing, exception message [Failure]
  8. 关于u8, u16, u32, u64
  9. 第十二届蓝桥杯题目和解答(C++B组)省赛
  10. 闪信霸屏短信USSD是什么?
  11. 高德地图SDK 配置key
  12. IT人才薪水“虚高” ,寡头垄断下小企业工程师告急[转]
  13. 市面上有哪些程序化软件?
  14. 一文带你了解Serverless架构及应用场景
  15. TeamViewer:一路前行,用技术实现领域更新
  16. 答疑解惑 | Linux GNU C 与 ANSI C 的区别
  17. java1.8 Lambda拉姆达表达式深入探究
  18. 弘辽科技:淘宝开店审核不通过怎么办?认证复核不通过怎么办?
  19. 利用AlphaFold进行蛋白质结构预测
  20. 发现panda(熊猫)对W32.Looked.I处理得不错

热门文章

  1. 按位与、或、非、异或总结
  2. 自然语言处理学习笔记-lecture06-词法分析与词性标注
  3. 【正则】956- 正则表达式有几种位置匹配模式?
  4. web网站如何实现兼容手机
  5. 5.mysql插入数据类型不匹配(Data truncation: Incorrect date value: ‘XX‘ for column ‘xx‘ at row 1 Query)
  6. python地图标点_python绘图 | 空间地图上散点气泡绘制
  7. VC6下miniblink应用开发简单实例
  8. 换个字体就能增强记忆力?这可能是一则科技趣闻
  9. CUDA 分块矩阵乘法
  10. fmincon函数 源代码