多线程——保证线程安全
目录
- 多线程——保证线程安全
- 含义
- 如何保证线程安全
- 具体方法
- volatile关键字
- 保证可见性
- 禁止重排序
- synchronized关键字
- 保证原子性
- 防止死锁
- 原因
- 后果
- 检查死锁
- 解决方法
不积跬步,无以至千里;不积小流,无以成江海。要沉下心来,诗和远方的路费真的很贵!
多线程——保证线程安全
含义
线程安全:指在多线程对一个共享资源同时进行操作的时候,所得到的结果每次都是一样的。
如何保证线程安全
方法:要保证线程安全,就必须保证线程同步
。保证线程的可见性
,有序性
和原子性
。
- 线程同步
线程同步的含义和字面意义相反。同步其实是线程“排队”的意思。就是让线程按照一定的顺序执行,
每一时刻,只有一个线程,对共享资源进行操作。
- 可见性
一个线程对共享资源的操作,所有的线程都可以看见。
以具体实例来说明。就好比一个线程修改了一个数据,其他线程立马知道该数据被修改了。
即就是在线程和主存之间有一个缓存,线程修改数据,是在缓存中修改,还需要在主存修改,而可见性就是立刻在主存中修改,防止其他线程读取时,发生数据错误。
- 有序性
就是代码的执行顺序是有序的,执行的顺序不会发生改变。
- 原子性
顾名思义,原子是一个不可分的整体。就是一个代码块,要么全部执行,要么全部不执行,只要其执行了,就无法被任何事务打断。
具体方法
volatile关键字
作用:保证线程可见性和禁止指令重排序。
保证可见性
实现原理:当一个变量被volatile修饰,一旦其发生改变,那么根据缓存一致性协议,其他线程的缓存都会失效,需要重新从内存中获取数据,就可以保证数据的准确性。就好比这个数据修改了,其他线程缓存失效,就知道了它被修改了,就要重新获取,即可见的含义。
不加volatile关键字
package com.hnu;public class Main2 {// static 静态变量 全局private static boolean flag = false;public static void main(String[] args) throws InterruptedException {new Thread(new Runnable() {//未停止,不知道已修改public void run() {while(true) {if(flag) {break;}}System.out.println("变量变化");};}).start();//主线程修改flag值Thread.sleep(1000);flag = true;}
}
线程先启动,启动后修改变量,未加关键字修饰,子线程不知道其变量值已经发生变化,即不可见,所以死循环无法停止。
加volatile关键字
package com.hnu;public class Main2 {// static 静态变量 全局private static volatile boolean flag = false;public static void main(String[] args) throws InterruptedException {new Thread(new Runnable() {//停止,知道已修改public void run() {while(true) {if(flag) {break;}}System.out.println("变量变化");};}).start();//主线程修改flag值Thread.sleep(1000);flag = true;}
}
加入关键字,首先先死循环,然后修改其值,知道其修改完成,然后调用,停止死循环,输出文字。可以证明其保证了可见性。
禁止重排序
实现原理:通过jvm给指令的前后加上内存屏障,屏障两边的指令不可以重排序,保证有序。
例子:单例模式
禁止重排序的经典案例就是单例模式的创建过程中的双重检测锁。
package com.hnu;public class Main2 {//自己对象,禁止重排序private volatile static Main2 main = null;//构造方法private Main2() {}//创建自己public static Main2 getInstance() {if(main == null) {//类锁,双重检测锁synchronized(Main2.class) {if(main == null) {main = new Main2();}}}return main;}public static void main(String[] args) {Main2 m1 = getInstance();Main2 m2 = getInstance();Main2 m3 = getInstance();System.out.println(m1 == m2);System.out.println(m1 == m3);System.out.println(m2 == m3);}
}
可知三个对象,都是同一个对象,内存地址相同。
synchronized关键字
作用:利用线程互斥来实现线程同步,即通过同一时刻只有一个线程可以访问(互斥),来实现线程的原子性,全部执行完,才能换线程执行,线程顺序执行(同步)。
synchronized
最主要的就是保持原子性
,保持原子性,最主要的就是线程同步
,同步最基本的方法就是加锁
,加锁最直接的就是加synchronized关键字
。
效率:synchronized在早期是一把重量级锁
,但是随着java
发展,如今的效率已经很高。例如i++不是原子操作,它分为三步:1.获取i的值 2.修改i的值 3.将修改的值赋予i 。如果在其外面加入synchronized
关键字,保证了每次只有一个线程可以修改i,那么就保证了i++在并发环境下的安全性。
保证原子性
上面的双重检测锁也使用了synchronized关键字,加同一个锁的线程同步互斥,里面的代码块在同一时刻,只有一个线程可以访问,所以保证了唯一实例。
防止死锁
原因
两个线程相互请求对方持有的资源,都不释放自己持有的资源,相互阻塞,导致死锁。
后果
至少有两个线程相互阻塞等待对方的资源。
检查死锁
使用jdk
工具jconsole
查看线程的状态。
解决方法
- 资源一次性分配
- 当线程满足条件时释放自己已占有的资源
- 资源有序分配
多线程——保证线程安全相关推荐
- 多线程下C#如何保证线程安全?
多线程编程相对于单线程会出现一个特有的问题,就是线程安全的问题.所谓的线程安全,就是如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码.如果每次运行结果和单线程运行的结果是 ...
- 按照顺序执行_问一个多线程的问题:如何才能保证线程有序执行?
面试的时候你是否经常被问到这样的问题: 你一般通过什么方式去控制线程的执行顺序? 碰到这样的问题,我的内心其实是很抵触的! 开什么玩笑?我怎么会控制它呢?我为什么要控制它? 其实不用慌,这个问题并不难 ...
- 多线程情况下如何保证线程安全
一.线程安全等级 其实线程安全并不是一个"非黑即白"单项选择题.按照"线程安全"的安全程度由强到弱来排序,我们可以将java语言中各种操作共享的数据分为以下5类 ...
- MFC 多线程及线程同步
一.MFC对多线程编程的支持 MFC中有两类线程,分别称之为工作者线程和用户界面线程.二者的主要区别在于工作者线程没有消息循环,而用户界面线程有自己的消息队列和消息循环. 工作者线程没有消息机制,通常 ...
- 它又来了!C**HashMap是如何保证线程安全的?会用不就完了?
欢迎关注方志朋的博客,回复"666"获面试宝典 阅读此篇文章,你需要有以下知识基础 Java内存模型,可见性问题 CAS HashMap底层原理 我们知道,在日常开发中使用的Has ...
- Java并发编程 synchronized保证线程安全的原理
文章转载致博客 blog.csdn.net/javazejian/- 自己稍加完善. 线程安全是并发编程中的重要关注点,应该注意到的是,造成线程安全问题的主要诱因有两点,一是存在共享数据(也称临界资源 ...
- java同步锁售票_Java基础学习笔记: 多线程,线程池,同步锁(Lock,synchronized )(Thread类,ExecutorService ,Future类)(卖火车票案例)...
学习多线程之前,我们先要了解几个关于多线程有关的概念. 进程:进程指正在运行的程序.确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能. 线程:线程是 ...
- 多线程:线程安全?如何实现?
多个线程不管以何种方式访问某个类,并且在主调代码中不需要进行同步,都能表现正确的行为. 线程安全有以下几种实现方式: 1)不可变 为什么是不可变? 不可变(Immutable)的对象一定是线程安全的, ...
- Java多线程02(线程安全、线程同步、等待唤醒机制)
Java多线程2(线程安全.线程同步.等待唤醒机制.单例设计模式) 1.线程安全 如果有多个线程在同时运行,而这些线程可能会同时运行这段代码.程序每次运行结果和单线程运行的结果是一样的,而且其他的变量 ...
- 多线程 空值线程数_【开发者成长】深入理解多线程编程
云栖号资讯:[点击查看更多行业资讯] 在这里您可以找到不同行业的第一手的上云资讯,还在等什么,快来! 为什么要使用多线程? 防止并发编程出错最好的办法就是不写并发程序 既然多线程编程容易出错,为什么它 ...
最新文章
- 符合标准的TreeView实现(Div+CSS+JS+ASP.NET)
- java_ant详解
- html语言的空格键,如何在如何在HTML中插入空格中插入空格
- python3爬虫实例-Python3 爬虫实例(一)-- 简单网页抓取
- java流的序列化_Java中的对象流和序列化介绍
- sqlite3数据库使用
- 两个文件比较 linux,linux下比较2个文件
- BrightHouse存储引擎
- C++调用C#编写的DLL【转】
- java+widthstep_关于IplImage中widthstep的大小与width,nchannels等的关系的问题
- 基于steamworks获取steam用户头像
- 小赛毛游C记——初识C语言(1)
- 华硕路由器流量管理QoS设置
- stm32:时钟系统
- 如何在电脑上安装虚拟机和系统。全网最全教程,不接受反驳。
- 离散数学中的x|y是什么意思?
- 【译】 SafetyNet: Google's tamper detection - Part 2
- Android logo图标的尺寸
- Xftp的介绍及下载安装教程
- Ubuntu下安装微信(非网页版)、TIM、QQ
热门文章
- 基于CC2430的基础实验5---时钟模式
- caj文档如何免费转换成pdf格式
- SQL Server 2005“错误1706。安装程序找不到需要的文件。请检查……”的处理办法
- Select at least one project的解决方法
- SharePoint CAML 查询时间类型
- Excel如何将一列数据转为一行?
- 秀米svg点击显示另一张图_时隔五年再用秀米,我发现了这个超强玩法
- 为什么公司宁愿花15k去重招一个应届生,也不愿意加薪5k留住老程序员?
- ACM常用数据结构小结与实现
- Java基础----交通工具的继承写法(面向对象的三大特征)