//不安全的买票
//线程不安全有负数,出现负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());//输出一下集合的大小,但是输出正常是不够,因为有时候会出来两个元素放在一个位置然后会覆盖掉
}
}