一:引言(特指单核)
所谓线程不安全,就是在共享数据时,不同的线程在执行时,出现数据的不准确,(以模拟抢票和模拟银行取钱为例),那么我们的线程不安全具体指的是什么呢?是指我们的一个线程还未来结束,就被cpu时间切片切换到其他线程了,最终会导致我们的数据不准确
二:实例分析
1.抢票
package com.wyj.three;
/**
*
* 线程不安全:出现负数,和相等的票数
*
* @author 86155
*
*/
public class Demo1_线程不安全示例一 {public static void main(String[] args) {// TODO Auto-generated method stub//同一个资源son3 p = new son3();System.out.println(Thread.currentThread().getName());//获取当前线程的名字//多个代理new Thread(p,"王小杰").start();new Thread(p,"王中杰").start();new Thread(p,"王大杰").start();}}class son3 implements Runnable{private int ticketnums = 10;@Overridepublic void run() {// TODO Auto-generated method stubwhile(true) {if(this.ticketnums < 0)break;try {Thread.sleep(1000);//模拟网络延迟 } catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.err.println(Thread.currentThread().getName()+"--->"+ticketnums--);}}}
分析:
这里的出现负数和相同的数就是我们的线程不安全,出现负数,那是因为3个人在抢最后一张票时,都在通过sleep(),进入阻塞状态,也就是线程被中断了,cpu时间切片,切换到其他线程执行了,那么等待阻塞状态结束,就如就绪状态,待cpu调度是,继续执行sleep()下面的代码,这是就会出现问题,第一个人阻塞状态结束后,可能会抢到票,那么接下来的人,阻塞状态结束后,继续执行sleep()下面的代码,因为是共享资源,唯一一张票已经被抢走了,剩下0,再来一个那就-1;
对于出现相等的票,那是1个人待阻塞结束后,从主存中拷贝原来的进度数据,但这时cpu时间切片还未切换到他,这是又有一个人从主存当中拷贝了数据,数据没变化,那当cpu调度到的时候就会出现相同的票**
2:实例二银行取钱
package com.wyj.three;
/*** 所谓线程不安全 就是发生在 共享资源上 * 银行取钱 两个线程在执行完 取钱的之后cpu时间片就切换了 就是一个线程还未执行完 就切换到另一个了,这样的话* 账户连续两次的取钱80,也就是剩下的钱为-60 当cpu时间切片切换回来时,余额就为-60;* * * @author 86155**/
public class Demo2_线程不安全示例二 {public static void main(String[] args) {//开个账户Account a = new Account(100, "结婚礼金");Drawing t1 = new Drawing(a,80, "me");Drawing t2 = new Drawing(a, 80, "wife");t1.start();t2.start();}
}//账户
class Account{int money;String name;public Account(int money, String name) {super();this.money = money;this.name = name;}
}//取款
class Drawing extends Thread{Account account;//取钱的账户;int getmoney;//取得钱int summoney;//取得总数public Drawing(Account account, int getmoney,String name) {super(name);this.account = account;this.getmoney = getmoney;}public void run() {// if((account.money-=getmoney) < 0)
// return ;
//
// try {
// Thread.sleep(1000);
// } catch (InterruptedException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }account.money-=getmoney;summoney+=getmoney;System.out.println(this.getName()+"-->账户余额:"+account.money);System.out.println(this.getName()+"-->到手的钱:"+summoney);}}
分析:
银行取钱 两个线程在执行完 取钱的之后cpu时间片就切换了 就是一个线程还未执行完 就切换到另一个了,这样的话
账户连续两次的取钱80,也就是剩下的钱为-60 当cpu时间切片切换回来时,余额就为-60;
三:总结
归根到底这些问题都是线程不同步导致的, 就是一个线程还未结束,就开始另外一个线程,在共享资源的背景下肯定会出现数据错误
如有疑问请留言呀