有关线程安全的探讨--final、static、单例、线程安全
- 什么样的代码是天生线程安全的?而不用加锁
- 线程是否安全的本质是什么?
- 什么是快速把一段代码变成线程安全的通用方法
- final static 单例 线程安全 之间的关系
- 这句话严格一些说可以是这样:线程使用在run( )方法中实例化的局部变量的方法,是线程安全的
- 继承并重写一个Thread类,然后在使用的时候实例化这个类,最后调用这个对象实例的start方法启动
- 这种方式的run方法中,其实能调用的东西就很少了
- 你在继承时加的成员变量。(完全不会有线程是否安全的问题,因为这个类就一个run()方法是多线程方法,就跟在run()中实例化的局部变量一样)
- 通过构造方法从外面传入的变量。(这种方式需要警惕!因为传递的是引用,如果你在线程中对这个引用指向的内容进行修改,那么会影响到原来的东西!)
- 使用其他的代码段(方法)
- 静态方法(类似单例模式)
- 实例方法——通过实例对象
- 使用其他的对象
- 静态对象
- 实例对象
- (两面两大点中,使用实例方法和实例对象都是线程安全的。而使用静态方法和静态对象时,是一定会冲突的)
- 所以总结一下,这种方式中
- 线程安全的有
- 在继承时加的成员变量
- 实例化其他对象,使用这个对象,或者使用这个对象的方法
- 不安全的有
- 通过构造方法从外面传入的变量
- 静态方法
- 静态对象
- 线程安全的有
- 这种方式的run方法中,其实能调用的东西就很少了
- 使用匿名内部类
- 这种方式,在上一种方式的继承上,只少了构造方法的方式,然后多了好几种危险的方式, 需要注意
- 所处方法中的局部变量
- 这个值得一提,本来这项是肯定会线程不安全,而且非常常用,所以危险指数五颗星的,但是JAVA特地为此限定了一条规则,就是这样的局部变量必须是final的,不能修改,于是这个就变得非常安全了
- 但这条其实可以通过引用类型绕过,就是另一回事了,其实也说明了它的不安全
- 所处类中的属性
- 所处类中的方法
- 所处方法中的局部变量
- 这种方式,在上一种方式的继承上,只少了构造方法的方式,然后多了好几种危险的方式, 需要注意
- 方法本身不会有问题,问题的根源是(普通方法、静态方法)方法使用了变量(相对全局变量,或者说叫可共享变量)【比如静态成员、类属性等等】
- 匿名类中更加危险,要谨慎调用
- 不能同时被多个线程调用
- 这个是最普通的,也是常规上我们的线程安全的含义
- 这个问题可以通过加锁解决
- 不能被多个线程调用(不同时也不行)
- 这个在第一类的程度上有所增加,不是常用的情况,可能你不仅是要使用变量,你还需要记录变量的值
- 这个问题一般是把相关变量变成ThreadLocal的
- 不能被超过一次地调用
- 这个的情况更加特殊
- 一般使用单例模式解决
- final
- 意思是,这个对象的值(基本类型就是值,引用类型是引用地址),不会再被改变
- 与线程安全的关系,如上文,一定程度上能使某些变量强制变得线程安全
- static
- 意思是,这个对象是一个全局变量了,你可以在多个地方,多个线程中调用到它,而且调用的是同一个它
- 与线程安全的关系,一般这种的变量很容易造成线程不安全的情况
- 单例
- 这首先是一种特殊的需求,就是某个类的实例在JVM中只能存在一个,跟前面的static,线程安全都不一样
- 与线程安全的关系。实现单例需要考虑复杂的多线程的情况,这个东西需要线程安全
- 因为创建一个 SimpleDateFormat实例的开销比较昂贵,解析字符串时间时频繁创建生命周期短暂的实例导致性能低下
- 在程序中我们应当尽量少的创建SimpleDateFormat 实例,因为创建这么一个实例需要耗费很大的代价。在一个读取数据库数据导出到excel文件的例子当中,每次处理一个时间信息的时候,就需要创建一个SimpleDateFormat实例对象,然后再丢弃这个对象。大量的对象就这样被创建出来,占用大量的内存和 jvm空间。
- 于是,就很容易想到,将 SimpleDateFormat定义为静态类变量,貌似能解决这个问题
- 于是这就引出了,SimpleDateFormat是非线程安全的,这样的使用方式可能引发并发线程安全问题
- SimpleDateFormat类内部有一个Calendar对象引用,它用来储存和这个SimpleDateFormat对象(叫sdf)相关的日期信息,例如sdf.parse(dateStr), sdf.format(date)
- 诸如此类的方法参数传入的日期相关String, Date等等, 都是交友Calendar引用来储存的
- 这样就会导致一个问题:如果你的sdf是个static的, 那么多个thread 之间就会共享这个sdf, 同时也是共享这个Calendar引用, 并且, 观察 sdf.parse() 方法,你会发现有如下的调用:
- Date parse() {
- calendar.clear(); // 清理calendar
- ... // 执行一些操作, 设置 calendar 的日期什么的
- calendar.getTime(); // 获取calendar的时间
- }
- 这里会导致的问题就是:如果 线程A 调用了 sdf.parse(), 并且进行了 calendar.clear()后还未执行calendar.getTime()的时候,线程B又调用了sdf.parse(), 这时候线程B也执行了sdf.clear()方法, 这样就导致线程A的的calendar数据被清空了(实际上A,B的同时被清空了). 又或者当 A 执行了calendar.clear() 后被挂起, 这时候B 开始调用sdf.parse()并顺利i结束, 这样 A 的 calendar内存储的的date 变成了后来B设置的calendar的date
- 你肯定是喜欢使用匿名内部类的,以这个为基础
- 注意如果是调用所在方法中的局部变量,尽量不要绕过final机制,如果需要绕过,而且会对这个局部变量进行修改的话,那一定是知道不会多个这样的线程同时运行(比如作为UI主线程外的一个子线程,这个子线程只会有一个)
- 不要尝试修改不是在自己内部实例化出的对象的值(只能改局部变量的值)(尽量使用局部变量)
- 你还喜欢使用静态工具方法,所有的静态工具方法中使用变量尽量使用局部变量(for循环中的i++ 是没有问题的),尽量少地使用静态变量,更不要尝试对静态变量的值进行修改
有关线程安全的探讨--final、static、单例、线程安全的更多相关文章
- 探讨一下Java单例设计模式
所谓单例模式,简单来说,就是在整个应用中保证只有一个类的实例存在.就像是Java Web中的application,也就是提供了一个全局变量,用处相当广泛,比如保存全局数据,实现全局性的操作等. 1. ...
- Java线程和多线程(五)——单例类中的线程安全
单例模式是最广泛使用的创建模式之一.在现实世界之中,诸如Databae的连接或者是企业信息系统(EIS)等,通常其创建都是受到限制的,应该尽量复用已存在对象而不是频繁创建销毁.为了达到这个目的,开发者 ...
- Android单例线程池
package com.jredu.schooltong.manager; import java.util.concurrent.ExecutorService;import java.util.c ...
- Spring中构造器、init-method、@PostConstruct、afterPropertiesSet孰先孰后,自动注入发生时间以及单例多例的区别、SSH线程安全问题
首先明白,spring的IOC功能需要是利用反射原理,反射获取类的无参构造方法创建对象,如果一个类没有无参的构造方法spring是不会创建对象的.在这里需要提醒一下,如果我们在class中没有显示的声 ...
- static实现单例的隐患
1. 前言 Java的单例有多种实现方式:单线程下的简单版本.无法在指令重排序下正常工作的Double-Check.static.内部类+static.枚举--.这篇文章要讨论的,是在使用static ...
- Swift百万线程攻破单例(Singleton)模式
一.不安全的单例实现 在上一篇文章我们给出了单例的设计模式,直接给出了线程安全的实现方法.单例的实现有多种方法,如下面: class SwiftSingleton { class var shared ...
- Java设计模式之单例
一.Java中的单例: 特点: ① 单例类只有一个实例 ② 单例类必须自己创建自己唯一实例 ③ 单例类必须给所有其他对象提供这一实例 二.两种模式: ①懒汉式单例<线程不安全> 在类加载时 ...
- 创建类模式(五):单例(Singleton)
定义 确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例. 单例模式一般情况下通过使用private的构造函数确保了在一个应用中只产生一个实例,并且是自行实例化. 和静态变量的区别 虽然 ...
- java中你确定用对单例了吗?
作为程序员这样的特殊物种来说,都掌握了一种特殊能力就是编程思想,逻辑比較慎重,可是有时候总会忽略到一些细节,比方我,一直以来总认为Singleton是设计模式里最简单的,不用太在意,然而就是由于这样的 ...
随机推荐
- Android学习之PopupWindow
Android的对话框有两种:PopupWindow和AlertDialog. 详细说明如下: AlertDialog是非阻塞式对话框:AlertDialog弹出时,后台还可以做事情: AlertDi ...
- JS 实现拖动效果
<html> <body style="margin:0px;"> <script src="http://ajax.googleapis. ...
- Linq EF 根据字符列表排序或List根据列表排序以及Linq查询类型转换
//model.BBSCategoryIDList=>{10,23,12}或者{1,3,2} //model.BBSCategoryIDs=>1,3,2或者10,23,12 //SqlFu ...
- Python学习(22):模块
转自 http://www.cnblogs.com/BeginMan/p/3183656.html 一.模块基础 1.模块 自我包含,且有组织的代码片段就是模块 模块是Pyhon最高级别的程序组织单元 ...
- 【ipad神坑】ipad麦克风听不到声音怎么回事 微信QQ语音视频对方都听不到
今天遇到了这个问题 说话听不见,但是敲击ipad,可以明显的听到击打的声音 siri也是可以听到 上网上找,大多都是说恢复设置,重启,隐私麦克风权限等解决方案 都是浪费感情 全部尝试过了,依然没有用. ...
- 【图算法】Dijkstra算法及变形
图示: 模版: /* Dijkstra计算单源最短路径,并记录路径 m个点,n条边,每条边上的权值非负,求起点st到终点et的最短路径 input: n m st et 6 10 1 6 1 2 6 ...
- springbatch---->springbatch的使用(七)
这里我们讲述一下springbatch中关于step层面上面的数据共享技术.而对街的人影都浸染在一片薄荷的白色中,由于无声,都好像经过漂染,不沾人间烟火. step的数据共享 关于springbatc ...
- vuex - 辅助函数学习
官网文档: https://vuex.vuejs.org/zh-cn/api.html 最底部 mapState 此函数返回一个对象,生成计算属性 - 当一个组件需要获取多个状态时候,将这些状态都声 ...
- Apache服务器SSL双向认证配置
以Win32版Apache与OpenSSL为例,介绍从创建数字证书到Apache配置的整个过程,希望对读者有所帮助. Apache是目前最流行的WEB服务器之一,借助OpenSSL库,我们可以在Apa ...
- isolinux.cfg 文件是干什么的
1. 首先光盘镜像也就是iso文件采用的是“ISO 9660 ”文件系统 . cd上的文件都存在这个简单的iso文件系统里,linux可以用mount -o loop 直接把*.iso文件mou ...