线程同步异常分析
当我们用多个线程去取得同一个对象中的某一个属性时,可能会出错,原因是很可能有一个或多个线程在同一时间去获取它。这是很危险的,好比对象就是一个银行账户,而属性就是该银行账户中的资金数目,当多个人对该账户同时取钱时,如果不采取措施,很可能会出现重复取钱事件。当然,从一方面来说,出现这样的问题,得益的是我们广大普通老百姓,但是,显然我们的国家并不希望这样的事情屡次发生。即使发生了,钱也不是你的。所以,为了防止类似“许霆案”的案件发生,有必要对这个问题进行解决。
什么?你不相信?
小二,上代码!(好嘞~新鲜热乎的代码)
packagecode;
/**
*分析线程同步中的异常及解决办法
*
*@authorAndre
*
*/
publicclass Test {
/**
*获得实现了Runnable接口的对象
*
*@paramstr
*/
publicRunnable getRunnable(String str) {
str="code." + str;
Runnablerb =null;
try{
rb= (Runnable) Class.forName(str).newInstance();
}catch (InstantiationException e) {
e.printStackTrace();
}catch (IllegalAccessException e) {
e.printStackTrace();
}catch (ClassNotFoundException e) {
e.printStackTrace();
}
returnrb;
}
/**
*让线程并发执行
*/
publicvoid runInGroup(Runnable rb, intn) {
for(int i = 0; i < n; i++) {
Threadtr =new Thread(rb);
tr.start();
}
}
publicstaticvoidmain(String[] args) {
Testtest =new Test();
//根据名称获取实现了Runnable接口的对象
Runnablerb = test.getRunnable("Plus2");
//启动线程
test.runInGroup(rb,40000);
}
}
Plus1类:即对操作不进行任何限制的
packagecode;
/**
*不进行任何同步措施
*
*@authorAndre
*
*/
publicclass Plus1 implementsRunnable {
privatelongnum= 0;
publicvoid run() {
add();
}
publicvoid add() {
//对num进行一百次加加操作
for(int i = 0; i < 100; i++) {
num++;
//每隔1000输出一次
if(num % 1000 == 0) {
System.out.println(" i =" +num);
}
}
}
}
问题分析:
可能你期待的结果是这样的……
课运行后,你得到的结果却是:
少加了几千个数!!!
当然啦,原因已经分析过了,即多个线程同时对一个对象的某个属性操作时,比如A,B线程同时获取到的是100,加上1以后,变成101,100经过两个线程调用add()方法后变成101。
解决办法:
解决的办法有 1.对add()方法加同步关键字synchronic
2.对关键代码段加锁
3.创建原子性的属性
一个一个来看
Plus2类:对add()方法加同步关键字synchronic
publicsynchronizedvoid add()
这样就可以保证同一时间只有一个线程在调用add()方法
Plus3类:对关键代码段加锁
先创建一个Object类对象,private char[] lockObj = new char[1];
再对代码段加上锁
synchronized (lockObj){
for(int i = 0; i < 100; i++) {
num++;
//每隔1000输出一次
if(num % 1000 == 0) {
System.out.println(" i =" +num);
}
}
}
这样每个线程都要获取到钥匙后才能打开锁,保证了实时性。
Plus4类:创建 原子性 的属性
所谓原子性,表面上理解就是 不可分割的。我们写的高级语言其实都要转化为机器指令才能被计算机执行,而在机器指令中,一个“i++”操作由:取值放到寄存器中、加一、放回内存三条机器指令组成。而线程不同步会出错的原因也在于此!
那么,只需要调用Java中的一个类 java.util.concurrent.atomic.AtomicLong即可实现。
线程同步异常问题分析到此为止!谢谢观看!