这样的代码是错误的,因为0线程进了run方法,其他线程进不去了。有锁,然后0线程进去一顿疯狂的打印。
那怎么改是正确的呢?看下图
现在的问题是public synchronized void show()这个方法用的哪一个锁呢?
函数需要被对象调用。那么函数都有一个所属对象的引用。就是this
所以同步函数使用的锁是this
通过程序验证一下,
使用两个线程来卖票
一个线程在同步代码块中
另一个线程在同步函数中
都在执行卖票动作
如果是同步的话,是不会出现错误的票,如果没有同步,那就会出现错误的票
我现在要创建两个线程,t1线程开启走同步代码块,t2线程开启走同步函数show(),那么怎么办呢?看上图红框有一个flag。
那么test类里这样写:
想一想这个代码有什么问题?这个主函数不算GC的话是有3个线程。1个主线程,一个t1,一个t2
那么当t1.start()刚读完之后,cpu切到了主线程,此时主线程有可能把t.flag = false 和t2.start()一块执行了。那么flag 就= false。 那么这样一来,run方法里的if肯定不走的。因为flag = false. 所以只能走else了。 所以上图代码完全有可能运行的结果都是走的同步函数show()。结果是有可能0线程全部卖完票。也有可能是0和1线程一块把票卖完。
那刚才说了
要这样的效果,那就意味着一个要走if,另一个要走else。那怎么设计代码呢?
主线程运行完t1.start()的时候,让主线程睡10毫秒,此时进程中只有线程t1。那么t1线程运行,默认的flag = true 所以t1.start()走的是if块的同步代码块。而当主线程切回来的时候,继续执行后续代码
所以t2就走的是else块的同步函数show。
打印结果是上图。注意,出现了0号票。是有问题的。
i-- 是先打印,然后再减。如果能打印出来0,那么就说明有线程安全问题。当tick = 1的时候,两个线程都进了if(tick>0)这个判断。然后陆续也醒了。先打印了tick = 1 ,打印完毕tick变成了 0,然后另一个线程也醒了,该打印的是tick--. 这时候tick已经是上一个线程运行完毕的tick-- = 1-- = 0了。然后再次运行 tick--的时候,打印的就是0,打印完毕tick变成了 -1。
注意 i-- 和 --i 的区别。 i--是先运算i,然后减。也就是说 当tick = 1的时候 打印 tick -- 的值就是 1,打印完毕后,tick才变成0
有问题说明是不同步。那什么情况下才同步呢?
首先要有2个以上的线程,其次两个锁的对象都得是this,上图代码中同步代码块里的锁是obj的,show方法上的锁是this的。这两个锁的对象都不一样。如果把同步代码块中的obj换成this,那么程序不会出现问题。
为了方便我把tick设置为10,打印结果如下
这样也就说明了同步的时候是同一个锁,把同步代码块中的obj改成this后运行结果是上图,说明了程序安全,那也就侧面说明了同步函数用的锁也是this。只有代码块和函数使用同一个锁的时候,程序才能安全运行。反证法。
如果您发现该资源为电子书等存在侵权的资源或对该资源描述不正确等,可点击“私信”按钮向作者进行反馈;如作者无回复可进行平台仲裁,我们会在第一时间进行处理!
添加我为好友,拉您入交流群!
请使用微信扫一扫!