多线程在提高运行效率的同时,也带来了并发问题,所谓并发问题就是多线程操作共享资源,导致数据状态异常。
以买票为例,10个人登录了12306,但余票只有5张。
- 初始状态有5张票,用户1来买,余票为5,付钱准备出票
- 这时用户2也来买,由于票还没出,所以查询发现余票仍未5,付钱准备出票
- 此时用户1出票,余票减一变为4
- 用户2也出票了,余票减一也变为了4
问题就出在这里,现在实际只有3张票,但余票却显示为4张,余票作为一个共享资源,因为多线程,导致状态异常了,运行下列代码,会发现余票最终成为了负值。
代码示例:
public class Ticket {
public int total = 5;
public void buy() throws InterruptedException{
if(total > 0){
//模拟中间过程
Thread.sleep(100);
--total;
}
}
public static void main(String[] args) throws InterruptedException {
Ticket ticket = new Ticket();
TicketThread ticketThread = new TicketThread(ticket);
//10个人抢5张票
for(int i=0;i<10;i++){
new Thread(ticketThread).start();
}
//确保所有线程都执行完了
Thread.sleep(3000);
System.out.println("剩余:"+ticket.total);
}
}
public class TicketThread implements Runnable{
Ticket ticket = null;
public TicketThread(Ticket ticket) {
this.ticket = ticket;
}
@Override
public void run() {
try {
ticket.buy();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
那如何解决这个问题呢?我们可以为buy()方法加上synchronized关键字,保证某一时刻只能有一个线程在执行buy()方法,这就相当于让多线程排队,强制变成了单线程,这样就可以解决并发问题了。下一节我们将更细致的探讨synchronized关键字。