Java synchronized实例

本文探讨了一个多线程环境下并发买票的问题,通过实例分析了线程间资源竞争导致的票数异常现象,并提出了解决方案,确保了票数的正确性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

下面这个例子是一个多线程买票的错误示例:

public class SaleTicketMutiThread implements Runnable {
int tickets = 100;
int temp = tickets;
boolean flag = true;
@Override
public void run() {
  while (flag) {
   if (tickets > 0) {
    try {
     Thread.sleep(30);
    } catch (InterruptedException e) {
     e.printStackTrace();
    }
    sale();
   } else {
    flag = false;
    System.out.println(Thread.currentThread().getName() + "卖光了");
   }
  }
}
public synchronized void sale() {
  tickets--;
  System.out.println(Thread.currentThread().getName() + " 已卖"
    + (temp - tickets) + "张,系统还剩" + tickets + "张票");
}
/**
  * @param args
  */
public static void main(String[] args) {
  SaleTicketMutiThread st = new SaleTicketMutiThread();
  new Thread(st, "一号窗口").start();
  new Thread(st, "二号窗口").start();
  new Thread(st, "三号窗口").start();
  new Thread(st, "四号窗口").start();
}
}

最后会运行出的结果会出现负数:
......
四号窗口 已卖99张,系统还剩1张票
一号窗口 已卖100张,系统还剩0张票
一号窗口卖光了
三号窗口 已卖101张,系统还剩-1张票
四号窗口 已卖102张,系统还剩-2张票

二号窗口 已卖103张,系统还剩-3张票


分析:

    当线程1 执行到sleep时候,线程2有机会占用cpu(也可能是线程3、线程4),线程2执行到sleep时候,线程3有机会占用cpu(也可能是线程4),线程3到sleep时候,线程4有机会占用cpu,线程4到sleep时候,线程1可能刚好醒来,继续向下执行,调用sale方法,执行tickets-- ,其他线程也陆续的醒来,执行tickets-- ,当tickets=1的时候,假设是线程1 在运行,判断 1>0 ,条件成立,线程1 执行到sleep时,让其线程2、3、4有机会执行,这时候tickets的值还是1,因为 条件判断语句之后就是sleep,故所有的线程都有机会进入到条件块中,所以每个线程都有调用sale方法,即使tickets=0时,tickets还会自减三次。 也就是票数会出现 -1 、-2 、-3的情况 。

解决方法:

将取票后sleep与票数减一同步处理,就可以避免最后一张票卖出去却因票数未减一而导致其他窗口取票动作。

修改后成功运行:

public class SaleTicketMutiThread implements Runnable {
int tickets = 100;
int temp = tickets;
boolean flag = true;
@Override
public void run() {
    ticket();
}
public synchronized void ticket()
{
  while (flag) {
   if (tickets > 0) {
    
   try {
     Thread.sleep(30);
    } catch (InterruptedException e) {
     e.printStackTrace();
    }
    sale();
   } else {
    flag = false;
    System.out.println(Thread.currentThread().getName() + "卖光了");
   }
  }
}
public void sale() {

  tickets--;

  System.out.println(Thread.currentThread().getName() + " 已卖"
    + (temp - tickets) + "张,系统还剩" + tickets + "张票");
}
/**
  * @param args
  */
public static void main(String[] args) {
  SaleTicketMutiThread st = new SaleTicketMutiThread();
  new Thread(st, "一号窗口").start();
  new Thread(st, "二号窗口").start();
  new Thread(st, "三号窗口").start();
  new Thread(st, "四号窗口").start();
}
}

最后会运行出的结果:
......
四号窗口 已卖99张,系统还剩1张票
一号窗口 已卖100张,系统还剩0张票
一号窗口卖光了


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值