在大致知道多线程的概念后,我们引入火车售票口售票的例子来学习线程的使用。
如何在java中实现并发式地卖票?
就像生活中那样,几个窗口卖同一堆票,互不干扰
我们先写出票类
public class Tickets {
private int num=0;
public Tickets() {
}
public Tickets(int num) {
this.num = num;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
}
再建立service类写入卖票的操作
public class Service {
public void sale(Tickets t){
int num=t.getNum();
if(num>0){
System.out.println("窗口在卖第"+num+"张票,剩下"+--num+"张票");
}
t.setNum(num);
}
}
接下来新建windows类,作为售票的窗口,也是我们程序的主类
public class Windows {
public static void main(String[] args) {
Tickets t=new Tickets(100);
Service s=new Service();
new Thread(()->{
while (t.getNum()>0){
s.sale(t);
}
},"窗口1").start();
new Thread(()->{
while (t.getNum()>0){
s.sale(t);
}
},"窗口2").start();
}
}
窗口1,窗口2两个线程,重写了run方法,再调用start(),开辟了两块独立的栈内存。
就这样,我们简单还原了生活中卖票的情形,但运行结果却不尽人意。
窗口2在卖第46张票,剩下45张票
窗口1在卖第47张票,剩下46张票
窗口2在卖第45张票,剩下44张票
窗口1在卖第46张票,剩下45张票
窗口2在卖第44张票,剩下43张票
窗口1在卖第45张票,剩下44张票
窗口2在卖第43张票,剩下42张票
简单来说就是会出现卖的乱七八糟的情况
为什么会这样,对着service类的代码对那上面那个例子进行解读
public class Service {
public void sale(Tickets t,String w){
int num=t.getNum();
if(num>0){
System.out.println(w+"在卖第"+num+"张票,剩下"+--num+"张票");
}
t.setNum(num);
}
}
首先每一个时间点只能执行两个窗口中的其中一个,他们是并发的,不能在内存中同时进行。
但内存对于线程的执行却并非是执行完一个线程的全部代码,他可能没被执行完就让别的线程从内存中挤出去了。
屏幕上显示
窗口2在卖第46张票,剩下45张票
说明窗口2已经执行完打印语句,但是否执行这个
t.setNum(num);
不知道
_______________________________________________________
而
窗口1在卖第47张票,剩下46张票
说明窗口1此时在内存里看到的票数是47,但也不知道是否设置票数
_______________________________________________________
窗口2在卖第45张票,剩下44张票
这句就说明窗口2已经设置了票数,改为45
_______________________________________________________
窗口1在卖第46张票,剩下45张票
说明窗口1在上一次并未改票数,这时才执行t.setNum(num);将票数又改回了46
_______________________________________________________
所以就是这样,我们的程序出现了大问题
怎样解决,很简单,只要一个关键字 synchronized
public class Service {
public synchronized void sale(Tickets t,String w){
int num=t.getNum();
if(num>0){
System.out.println(w+"在卖第"+num+"张票,剩下"+--num+"张票");
}
t.setNum(num);
}
}
再运行程序,就发现线程运行的井井有条,不会重票
synchronized就像一把锁,JAVA使用锁机制保证同步代码块或方法的“原子性”,即保持整体性,不可分割。
具体synchronized的作用原理就不再探讨了,本篇之探讨以上问题的解决。