最近在学习毕向东老师的java基础课程,目前学到的多线程的这一部分,以下权当做一个总结。
一、引出
对于火车站来说,卖票是每天都会发生的事情,然而如果只有一个窗口卖票,单线程来操作将会导致效率很低,如果多窗口操作就会使效率大幅度提升,此处我们假设只有100张票,两个卖票窗口,代码如下:
执行后结果如图:
会发现,最后一行居然出现了一个num=0的情况,可是在我们的程序中明明已经做了对num大于0的检查,此处即为将要解决的问题。
二、线程同步
以上的程序出现了num等于0的情况,此情况出现的原因如下:当num=1时线程1执行到第五行,if判断其值大于0,接下来该线程休息10ms,在其刚开始休息时,线程2获得cpu执行权,又执行到if处,判断其值同样大于0(此时其值还是1),接下来线程2休息,线程1又得到执行权,打印出1,同时num变为0,然后线程2获取执行权,打印出0。造成这种情况的原因在于不同的线程操纵了同样的数据,比如这里的示例,两个示例同时操作票数,为了解决这个问题我们需要加入一把锁,让这把锁把要操作的数据进行锁定,这样当一个线程将其锁定时,其它的线程是无法操作的,只有当那个线程执行完成并释放锁之后才能进行操作,而这就称为线程同步。
1)同步代码块
同步代码码是第一种线程同步的方式,其代码如下:
其执行结果如下:
无论执行多少次都不会出现num为0的情况。但在此处请注意:切勿把obj对象定义在run方法内部,如果那样,则这个锁将不会是同一把锁,这种同步就没有意义了。就好比两个人在火车上去卫生间,a在1号车,b在10号车,那么a无论怎么锁1号车的卫生间,都不会影响到b.
2)同步函数
同步函数指的是将整个函数进行锁定,代码改造如下:
其执行结果也不会出现0的情况,与同步代码块的原理基本一致,但请注意同步函数锁定的是当前对象(即this),而同步代码块锁定的是一个对象。除此外没有别的区别。
三、死锁
首先看代码:
主线程:
执行结果如下:
这种现象就是死锁,到这种情况,纯种1与2均不能继续向下运行了。总结死锁发生条件:两把锁,线程1将第一把锁锁住后,想再锁住第二把锁,但第二把锁却被其它的线程锁住了,而这个线程又想锁住第一把锁。