内容目录:
java 并发问题
正文
前一篇文章我们了解了所谓的线程之间的通信,其实就是线程获取内存的数据,然后通过一问一答的形式,模拟一种通信的假象,所以归根到底,线程就是对内存的操作,那么现在我们通过一个经典问题-车站卖票,来引出本文的主题-java并发问题
问题:车站卖票,每个站台都会发售车票,然后旅客买票,每一张票都有自己唯一的编号,卖过了的票就不能再重复卖,车站有这么多卖票的方式,这么多的旅客同时买票,如何才能保证卖的每一张票都不重复呢?
翻译成程序就是,同一块内存中的对象(车票),用多个线程处理,如何保证数据不相互干扰,即我们通常听见的线程干扰
编码思路:
一、建模,卖票是一个动作,这个动作由车站执行,先建立车站类
package test2;public class Station{ @Override public void run() { }
}
二、车站具体的行为是卖票,卖票是一个具体的动作,而且也不止一个车站卖票
package test2;
public class Station extends Thread{
@Override public void run() { }}
三、卖票是一个动作,那么这个动作的对象是票,并且票的总数是确定的
package test2;
public class Station extends Thread{
static int tikets = 30; // 票数 , 票是归车站所有
@Override
public void run() { }}
四、编写车站具体卖票的行为
1、判断是不是还有余票,有余票就卖,没有余票就不卖(这不是废话嘛)
2、票的总数要随着卖的数量减少,即卖掉一张总数就减少一张(就知道说一些废话)
3、不能重复卖同一张票,即卖过了不能重复卖(这是问题的关键),如何保证不重复呢?
答案:锁(下一章我们详细讲解锁),将票这个对象锁起来,当一个车站在操作这张票的时候,其他的车站不允许在操作这张票了
package test2;public class Station extends Thread{ static int tikets = 30; static Object o = "a"; Station(String name){ super(name); } @Override public void run() { while(tikets > 0){ synchronized(o){ if(tikets > 0){ System.out.println("站台"+getName()+",卖出了第"+tikets+"张票"); tikets--; }else{ System.out.println("卖完了"); } } try { Thread.sleep(1 * 1000); } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) { Station station1 = new Station("上海站"); Station station2 = new Station("北京西站"); Station station3 = new Station("广州南站"); station1.start(); station2.start(); station3.start(); }
}
结果:
站台北京西站,卖出了第30张票站台上海站,卖出了第29张票站台广州南站,卖出了第28张票站台上海站,卖出了第27张票站台广州南站,卖出了第26张票站台北京西站,卖出了第25张票站台上海站,卖出了第24张票站台广州南站,卖出了第23张票站台北京西站,卖出了第22张票站台上海站,卖出了第21张票站台北京西站,卖出了第20张票站台广州南站,卖出了第19张票站台广州南站,卖出了第18张票站台上海站,卖出了第17张票站台北京西站,卖出了第16张票站台广州南站,卖出了第15张票站台北京西站,卖出了第14张票站台上海站,卖出了第13张票站台上海站,卖出了第12张票站台广州南站,卖出了第11张票站台北京西站,卖出了第10张票站台广州南站,卖出了第9张票站台上海站,卖出了第8张票站台北京西站,卖出了第7张票站台上海站,卖出了第6张票站台广州南站,卖出了第5张票站台北京西站,卖出了第4张票站台广州南站,卖出了第3张票站台北京西站,卖出了第2张票
站台上海站,卖出了第1张票
由上可知,解决并发问题的关键是学会使用锁,下一章我们详细讲解线程中的锁
