刚毕业的时候,总是搞不清什么是线程安全,只记得网上说,只要方法做到可重入,就是线程安全的,晕头晕脑,一头雾水。
今年读Java并发编程,对并发有了进一步的了解,结合我们项目的实际应用,谈一下我对线程安全的认识。
一、共享变量(share varibles)引起线程安全
如果没有共享,就不会有线程安全问题。比如,你写的就是一个简单的helloword程序,不会有线程安全问题。但如果你的程序是一个web项目,并且里面有一个全局适用的缓存对象,那么就会涉及到线程安全问题。
下面是一个静态方法,根据code_id,得到code_name的方法。
public class CodeHelper { private static Map<Integer,String> CODE_DATA ; public static void initCode(){ //load from db .. } public static String getCodeNameById(int codeId){ if(CODE_DATA==null){ initCode(); } return CODE_DATA.get(codeId); } }
变量CODE_DATA就会涉及到线程安全问题。我们考虑,如果同时有两个线程调用getCodeNameById的方法,那么initCode方法就会被执行两边,而这却不是我们希望看到的。所以说,只要涉及到静态变量,我们就要小心了,静态变量,有可能存在线程安全问题。
二,单实例引起线程安全
我们知道,spring中的bean默认都是单实例(prototype=singleton)的,也就是说,spring里面的bean,其所有的成员变量都基本上是与静态变量是类似的。bean的任何方法,都必须代是可重入的,而不能在某个方法里面,设置bean的某个值,并且依赖其状态。比如,下面的代码就会出现线程问题。
public class JavaBean { private String myname; public void aservice(String paraName,int otherPara){ //在spring的默认配置下在这里设值,另一个方法使用是错误的 this.myname=paraName; bservice(); } private void bservice() { String goodName= this.myname; //other work } public String getMyname() { return myname; } public void setMyname(String myname) { this.myname = myname; } }
如果有两个线程A和B,同时进入aservice,A线程设置myname="AName",然后在执行到bservice线程阻塞,此时B线程进入,将myname="BName",然后进入bservice得出正确结果而退出。B线程执行后,myname="BName",A线程恢复,在bservice的方法执行时,使用的myname="BName",计算肯定会出错。但如果你每次使用JavaBean的时候,都是new一个,就不会存在线程安全的问题了。
虽然线程安全是一个不是很容易理解的话题,但上面两个例子却反映了两个最普遍的线程安全问题。遇到线程问题,最快的解决方法就是去掉变量共享。单线程的程序,永远不会出现线程安全问题。
相关推荐
内含各种例子(vc下各种控件的使用方法、标题栏与菜单栏、工具栏与状态栏、图标与光标、程序窗口、程序控制、进程与线程、字符串、文件读写操作、文件与文件夹属性操作、文件与文件夹系统操作、系统控制操作、程序...
使用说明如下:函数声明和调用方法与DLL命令一致;“库文件名”以.lib或.obj为后缀的将被视为静态库,可使用绝对路径或相对路径(相对当前源代码所在目录),如依赖多个静态库请分别列出并以逗号分隔;“在库中的...
书中从并发性和线程安全性的基本概念出发,介绍了如何使用类库提供的基本并发构建块,用于避免并发危险、构造线程安全的类及验证线程安全的规则,如何将小的线程安全类组合成更大的线程安全类,如何利用线程来提高...
实例202 取消磁盘共享 261 实例203 检查驱动器容量 262 实例204 检测磁盘是否准备好 263 实例205 图表显示磁盘容量 264 实例206 格式化磁盘 265 6.3 系统控制 266 实例207 怎样隐藏鼠标 266 实例208 ...
2.6.2 函数的多线程安全性 34 2.6.3 代码的中断级 36 2.6.4 WDK中出现的特殊代码 37 练习题 38 第3章 串口的过滤 40 3.1 过滤的概念 41 3.1.1 设备绑定的内核API之一 41 3.1.2 设备绑定的内核API之二 43 3.1.3 生成...
2.6.2 函数的多线程安全性 34 2.6.3 代码的中断级 36 2.6.4 WDK中出现的特殊代码 37 练习题 38 第3章 串口的过滤 40 3.1 过滤的概念 41 3.1.1 设备绑定的内核API之一 41 3.1.2 设备绑定的内核API之二 43 3.1.3 生成...
2.6.2 函数的多线程安全性 34 2.6.3 代码的中断级 36 2.6.4 WDK中出现的特殊代码 37 练习题 38 第3章 串口的过滤 40 3.1 过滤的概念 41 3.1.1 设备绑定的内核API之一 41 3.1.2 设备绑定的内核API之二 43 3.1.3 生成...
2.6.2 函数的多线程安全性 34 2.6.3 代码的中断级 36 2.6.4 WDK中出现的特殊代码 37 练习题 38 第3章 串口的过滤 40 3.1 过滤的概念 41 3.1.1 设备绑定的内核API之一 41 3.1.2 设备绑定的内核API之二 43 3.1.3 生成...
内含各种例子(vc下各种控件的使用方法、标题栏与菜单栏、工具栏与状态栏、图标与光标、程序窗口、程序控制、进程与线程、字符串、文件读写操作、文件与文件夹属性操作、文件与文件夹系统操作、系统控制操作、程序...
3.3.3实例成员变量和静态成员变量114 3.4方法的定义和实现116 3.4.1方法的声明117 3.4.2创建方法体与return语句117 3.4.3局部变量和成员变量的区别119 3.4.4方法的访问权限121 3.5方法的调用121 3.5.1方法...
内含各种例子(vc下各种控件的使用方法、标题栏与菜单栏、工具栏与状态栏、图标与光标、程序窗口、程序控制、进程与线程、字符串、文件读写操作、文件与文件夹属性操作、文件与文件夹系统操作、系统控制操作、程序...
内含各种例子(vc下各种控件的使用方法、标题栏与菜单栏、工具栏与状态栏、图标与光标、程序窗口、程序控制、进程与线程、字符串、文件读写操作、文件与文件夹属性操作、文件与文件夹系统操作、系统控制操作、程序...
内含各种例子(vc下各种控件的使用方法、标题栏与菜单栏、工具栏与状态栏、图标与光标、程序窗口、程序控制、进程与线程、字符串、文件读写操作、文件与文件夹属性操作、文件与文件夹系统操作、系统控制操作、程序...
2.6.2 函数的多线程安全性 34 2.6.3 代码的中断级 36 2.6.4 WDK中出现的特殊代码 37 练习题 38 第3章 串口的过滤 40 3.1 过滤的概念 41 3.1.1 设备绑定的内核API之一 41 3.1.2 设备绑定的内核API之二 43 3.1.3 生成...
内含各种例子(vc下各种控件的使用方法、标题栏与菜单栏、工具栏与状态栏、图标与光标、程序窗口、程序控制、进程与线程、字符串、文件读写操作、文件与文件夹属性操作、文件与文件夹系统操作、系统控制操作、程序...
2.6.2 函数的多线程安全性 34 2.6.3 代码的中断级 36 2.6.4 WDK中出现的特殊代码 37 练习题 38 第3章 串口的过滤 40 3.1 过滤的概念 41 3.1.1 设备绑定的内核API之一 41 3.1.2 设备绑定的内核API之二 43 3.1.3 生成...