想要解决线程安全问题,首先要知道为什么会造成线程不安全?

在单线程中,我们从来没有提到个线程安全问题,线程安全问题是只出现在多线程中的一个问题。因为多线程情况下有共享数据,每个线程都共享这些数据并对这些数据进行修改,当需要修改数据进行写入时,还有线程调度的交叉执行,还有内存模型的原因引起了不安全问题。

要保证线程安全是一件很难的事,一般我们着眼于以下三个方面:

(三个核心)

1.原子性

2.可见性

3.重排序问题

首先来解释一下,什么是原子性,可见性,重排序问题?

原子性,一段不可再分的代码片段,要么全部执行要么都不执行。(一句代码不一定就是原子的,例如a=b,将b从主内存中加载到工作内存,再将b的值赋给a,最后将a保存到主内存中,很明显是三步。)

可见性,所有的数据存在主内存中,每个线程有自己的工作内存,工作时将数据从主内存中加载到工作内存(这样做有利于提高运行效率),这时候,如果本线程将数据做了修改,其他线程及时的看到了,这就叫可见的(但往往本线程已经修改了数据,在其他线程中还是用的是旧的数据,这就发生了错误,就是不安全问题。)

重排序问题,在单线程中我们的都是按照顺序执行的,但是在多线程中,CPU/编译器/JIT会对代码运行顺序进行一定的调整(按照更加合适的方式执行,优化),但是这样就没办法保证结果的正确性,会出错,这就是代码重排序问题。

为了解决这些不安全问题而产生了synchronized和volatile关键字

接下了我们看看synchronized和volatile是如何保证安全性的,以及学会使用方法,来保证我们自己写的代码的线程安全。

1.synchronized

先学习synchronized 的语法:

1)方法修饰符——和其他修饰符的使用类似

2)代码块——作为代码块出现

接下来,谈谈synchronized 是如何保证线程安全的?

synchronized 是通过给对象加锁,保证了原子性和可见性来使线程安全的,

先看给普通方法加锁,

锁是加在在堆里创建的对象上面,当一个线程抢占CPU成功时,检查该对象,发现锁是开的(锁初始状态下是开的状态),就给这个对象加锁,直到方法执行结束(正常/异常),释放锁。在当前线程加锁运行代码的过程中,不一定可以一直抢占CPU,如果自己的时间片用完了或者主动放弃CPU,线程调度到其他线程,而其他线程这时抢占CPU成功了,这时检查该对象(注意:和前面是同一对象,当前对象,this指向的那个对象)发现已经上锁,这时该线程直接放入阻塞队列,只有当这把锁被释放后,才能重新进入就绪队列,重新获得了抢占CPU的机会,每一把锁都有一个对应的阻塞队列。

再看给静态方法加锁,

给静态方法加的锁,是在放类的方法区里,加在类的元对象上面。

synchronized的代码表现:

| 表现 ---------- | 锁的对象 ------- | 何时加锁---- | 何时释放 - |

|修饰普通方法 | this -------------- | 进入方法---- | 退出方法 - |

|修饰静态方法 | 类名.class ----- | 进入方法 — | 退出方法-- |

| 代码块-------- |小括号引用指向 | 进入代码块 | 退出代码块 |

加锁保证了原子性,并在一定程度上保证了可见性。

在加锁时,所有线程会同步当前的数据,在释放锁时,数据又会同步一次,但是在加锁-解锁这个代码运行的过程中,没有保证可见性。

加锁内部的代码可以进行重排序,外部的代码也可以进行重排序,但是内部和外部之间是不相通的不可以交换代码执行顺序。

使用synchronized的缺点:理论上所有的线程安全问题都可以使用synchronized来解决,但是成本非常高。(不断的进行线程调度本身就会花费很多时间,而且,如果每次都是同一线程抢占CPU成功,其他线程就会一直处于阻塞-抢占的过程中)

在使用synchronized关键字时加锁时,要尽量把它放在合适的位置上,如果范围过大,将没有意义,即关注锁的粒度问题,粗粒度,细粒度。

2.volatile

语法:修饰变量

可以保证该变量的可见性问题(不再赘述)

可以部分保证代码的重排序问题(对象初始化,分为三步:new 、 对象初始化、对象赋值给引用。volatile可以保证这三步是顺序执行的)

关于原子性的一个总结:

基本数据类型里,

byte、int、Boolean、float、char、short作为字面量时是原子的,作为变量时不是原子的;

long、double在任何时候都不是原子的。(因为它们都是64位的在32位机运行时,分为低32位和高32位,不是一步执行的)

最后再提一点:单例模型:一个类只会生成一个对象(只有一个实例),大家共用的是同一个实例)

java和线程相关的关键字有哪些_Java中有哪些机制来保证线程安全?synchronized关键字和volatile关键字...相关推荐

  1. Java多线程学习二十六:原子类是如何利用 CAS 保证线程安全的?

    什么是原子类,以及它有什么作用. 在编程领域里,原子性意味着"一组操作要么全都操作成功,要么全都失败,不能只操作成功其中的一部分".而 java.util.concurrent.a ...

  2. 主线程 唤醒_Java等待唤醒机制统计子线程运行时间的方式及其疑问

    我想在主线程中获取子线程运行的时间,一种方式是使用join()方法,经验证是可行的: 但是我想试试等待唤醒机制,思路是:子线程启动后主线程等待,子线程结束后唤醒主线程,但是不太清楚为什么会报错,从运行 ...

  3. 【Java 并发编程】线程指令重排序问题 ( 指令重排序规范 | volatile 关键字禁止指令重排序 )

    文章目录 总结 一.指令重排序规范 二.指令重排序示例 总结 Java 并发的 333 特性 : 原子性 : 每个操作都是 不可拆分的原子操作 ; 在线程中进行 a++ 就不是原子操作 , 该操作分为 ...

  4. Java并发编程—volatile关键字(保证变量的可见性、有序性机制)

    原文作者:Matrix海子 原文地址:Java并发编程:volatile关键字解析 volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字,因为在程 ...

  5. Java基础——volatile关键字解析

    简介 volatile关键字虽然从字面上理解起来比较简单,但是要用好不是一件容易的事情.由于volatile关键字是与Java的内存模型有关的,因此在讲述volatile关键之前,我们先来了解一下与内 ...

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

    转自https://www.cnblogs.com/dolphin0520/p/3920373.html Java并发编程:volatile关键字解析 Java并发编程:volatile关键字解析 v ...

  7. java中volatile_java中volatile关键字的含义

    在java线程并发处理中,有一个关键字volatile的使用目前存在很大的混淆,以为使用这个关键字,在进行多线程并发处理的时候就可以万事大吉. Java语言是支持多线程的,为了解决线程并发的问题,在语 ...

  8. 【Java并发编程:volatile关键字之解析】

    Java并发编程:volatile关键字解析 - Matrix海子 - 博客园 在Java 5之前,volatile是一个备受争议的关键字:因为在程序中使用它往往会导致出人意料的结果.在Java 5之 ...

  9. java 传绝对路径无效_【Java并发005】原理层面:volatile关键字全解析

    一.前言 在Java 5之前,volatile是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果. 在Java 5之后,volatile关键字才得以重获生机. volatile关键字虽 ...

最新文章

  1. Android系列讲座(2):为TextView组件加上边框
  2. linux添加美式键盘,win8\win server 2012添加【中文--美式键盘】
  3. Discuz学习总结——部分bug解决方案
  4. 从商业视角理解数据:数据科学家的思维之路
  5. VISP视觉库识别AprilTag详细解读
  6. python编程语言能干什么-这 13个,1 行Python代码能干哪些事?
  7. openfire + spark + sparkweb + pandion 下载地址
  8. 将mysql的数据库导入到linux_linux 操作之一 如何在linux将本地数据*.sql文件导入到linux 云服务器上的mysql数据库...
  9. linux安装tf-gpu注意事项
  10. flutter中state详解
  11. JVM Attach机制实现
  12. LQ训练营(C++)学习笔记_常见动态规划模型
  13. 链接访问后刷新颜色回到初始_如何使链接可访问(提示:颜色不够)
  14. 2021年中国银发经济洞察报告
  15. OpenJDK与JDK的区别分析
  16. webStorm部分以及重要快捷键
  17. Combinations leetcode 组合问题
  18. 如何复制或导出托管磁盘
  19. Netty之Pipeline总结
  20. 最全java面试题及答案(208道)

热门文章

  1. 【MySQL】小表驱动大表
  2. Mac :谷歌浏览器 NET::ERR_CERT_INVALID 此证书已被撤消。网络错误和攻击行为通常是暂时的,因此,此网页稍后可能会恢复正常
  3. linux句柄过大导致无法登陆
  4. Flink eventTime案例无输出
  5. Drools 7.x Rate算法
  6. WinForm中日期控件开窗
  7. Java lang3的 StringUtils.isNumeric(str)不能识别负数和小数
  8. JavaScript模拟call和apply的实现
  9. [转]SQL中的case when then else end用法
  10. git安装和GitHub使用