多线程-线程同步-三大不安全例子


//不安全的买票
//线程不安全有负数,出现负1的情况就是没有同步加锁,因为线程都有自己的工作内存,当我们的票只有一张时,三个线程都是看得到的,当其中一个线程把这个票拿到自己的工作内存中购买了,另一个线程也同时把票自己的工作内存购买,但是因为上一个线程已经买了,所以当第二线程购买时票数变为0了,所以他还在购买,这时他拿到票数是为0,那第三个线程拿的票数就是变成负数了,他们都认为还有票,但是真正买完后都变成负的了,所以这个时候我们要让他们变成队列然后加锁买
public class Main{
    public static void main(String[] args) {
        BuyTicket station=new BuyTicket();
        //创建三个线程共享一个买票资源
    new Thread(station,"").start();
    new Thread(station,"").start();
    new Thread(station,"").start();
        
        
        
    }
}
//买的类
class BuyTicket implements Runnable{
    //票数
    private int ticketNums=10;
    //创建一个循环停止的属性,外部停止方式
    boolean flag=true;
    public void run(){
        //买票
        while(flag){
            try {//下面抛出异常上面就要处理
                buy();
            } catch(Exception e) {
                System.out.println("异常");
            } 
            
        }
        
    }
    //买票的方法    
    private  void buy()throws InterruptedException{
        //判断是否有票
        if (ticketNums<=0){
            flag=false;
            return;
        } 
        //模拟延时
        Thread.sleep(100);
        
        System.out.println(Thread.currentThread().getName()+"拿到"+ticketNums--);
    }
}
//不安全的取钱
//两个人去银行取钱,账户
//sleep():可以放大问题的发生性
public class Main {
    public static void main(String[] args) {
    //账户
    Account acc=new Account(100,"理财基金");
    //创建银行对象,构造器中,传入账户及取钱金额及名字
    Drawing you=new Drawing(acc,50,"");
    Drawing gir=new Drawing(acc,100,"");
    you.start();
    gir.start();
    
    }
}
//账户
class Account{
    int money;//余额
    String name;//卡名
    
    public Account(){}

    public Account(int money,String name){
        this.money=money;
        this.name=name;
    }
    
}
//银行:模拟取款
class Drawing extends Thread{
    
    Account account;//想要取钱,就得有账户
    
    //取了多少钱
    int drawingMoney;
    //现在手里有多少钱
    int nowMoney;
    
    public Drawing(Account account,int drawingMoney,String name){
        super(name);//获取线程的名字,因为继承了Thread是可以用父类方法来获取的 
        this.account=account;
        this.drawingMoney=drawingMoney;
        
    }
    
    //取钱:重写run
    public void run(){
        //判断有没有钱
        if (account.money-drawingMoney<0){//如果账户里的钱减去要取的钱小于0,就是不够
        System.out.println(Thread.currentThread().getName()+":你的余额不足");
        return;
        } 
        try {
             //当如果账户有钱,我们进来后,都停一秒钟,这样就会让账户出现负数
        //为什么出现问题呢,因为这两个账户的内存都不一致的,当他们看到100时,是用时看到的,所以以为都能取完,这就导致了线程的不安全,只有让一个线程先执行完,再让其他线程进行执行,这样才会安全
Thread.sleep(1000); } catch(InterruptedException e) { System.out.println("有异常"); } //卡内余额=余额-你取的钱 account.money=account.money-drawingMoney; //你手里的线 nowMoney=nowMoney+drawingMoney; System.out.println(account.name+"的余额:"+account.money); //Thread.currentThread().getName()==this.getName),也是获取线程名称 System.out.println(this.getName()+"手里的钱"+nowMoney); } }
//线程不安全的集合


public class Main {
    public static void main(String[] args) {
        Listlist=new ArrayList();
        for (int i=0;i<1000 ;i++ ){
            new Thread(()->{//创建1000个线程
                list.add(Thread.currentThread().getName());//把线程的名字添加到集合中
            }).start();
        } 
        System.out.println(list.sixe());//输出一下集合的大小,但是输出正常是不够,因为有时候会出来两个元素放在一个位置然后会覆盖掉
    }
}

相关