简介
- 产生安全问题的条件
- 存在共享数据 (也称临界资源)
- 存在多条线程共同操作共享数据
- 安全问题原因分析
- 首先要知道线程如何访问临界资源的:一个线程建立,具有了线程自己的内存空间,当需要访问临界资源时(对临界资源进行读取,计算、重新赋值等操作),会先从临界资源中取得一个所需数据的备份到自己的内存空间中,然后在线程操作中对备份数据进行读取,计算、重新赋值等操作,然后得到一个新的数据,再将这个数据写回到临界资源中覆盖旧的数据。
- 显然在取得备份到重新写回覆盖这段时间内,如果有新的线程对临界资源进行访问,此时就可能会造成数据的不一致,产生安全问题。
安全问题示例
code1:
/**
* 测试多线程并发访问时的不安全问题
* 1.多线程访问同一个数据,只加简单的条件判断没有用
* @author dxt
*
*/
public class UnsafeTest {
public static void main(String[] args){
Account account = new Account(100, "dxt");
Drawing me = new Drawing(account, 80);
Drawing me2 = new Drawing(account, 80);
new Thread(me).start();
new Thread(me2).start();
}
}
/**
* 账户
* @author dxt
*
*/
class Account{
int money; //账户金额
String name;
public Account(){}
public Account(int money, String name){
super();
this.money = money;
this.name = name;
}
}
/**
* 模拟取款
* @author dxt
*
*/
class Drawing implements Runnable{
Account account; //取钱的账户
int getMoney; //所取得钱数
int getTotalMoney; //取钱总数
int packetMoney; //口袋中的钱
public Drawing(Account a, int getMoney){
super();
this.account = a;
this.getMoney = getMoney;
}
/**
* 实现run()方法
*/
public void run(){
//对账户金钱进行控制(账户余额不能小于0),实际对于多线程没有作用
if(account.money - getMoney < 0){
return;
}
try{
Thread.sleep(200);
}catch(InterruptedException e){
e.printStackTrace();
}
account.money -= getMoney;
packetMoney += getMoney;
System.out.println(Thread.currentThread().getName() + "账户余额:" + this.account.money);
System.out.println(Thread.currentThread().getName() + "身上现金:" + this.packetMoney);
}
}
结果:
code2:
import java.util.ArrayList;
import java.util.List;
/**
* 测试多线程并发访问时的不安全问题
* 容器访问冲突
* @author dxt
*
*/
public class UnsafeTest02 {
public static void main(String[] args){
List<String> list = new ArrayList<String>();
//容器中装10000个对象
for(int i=0; i<10000; i++){
//匿名内部类
new Thread(new Runnable(){
public void run(){
list.add(Thread.currentThread().getName());
}
}).start();
}
Thread.sleep(1000);
System.out.println(list.size()); //硬挨为10000,实际要小于10000
}
}
结果: