刘小爱v 自学Java第33天:用一个案例向你说明什么是线程同步?( 二 )
我们再看看控制台输出情况:

文章图片
票的打印确实是有序的了 , 也没有重复卖票 。
但是现在问题又来了:第0张票和第-1张票怎么来的?
为什么会出现这种情况?
我们仔细看看while循环的代码:

文章图片
现在窗口壹在售卖第1张票 , 卖完之后票数ticket等于0了 。
但是窗口贰和窗口叁它们两个线程在干嘛?
它们早就已经进入while循环了 , 只不过因为先前synchronized锁住的代码块 , 窗口壹在里面 , 它们没法进去 , 只能等在synchronized外面 , 但是它们已经在while循环里面 。
我们仔细分析下这个流程:
(1)窗口壹打印完第1张票 , ticket变成了0 , 通过while循环的判断语句(ticket>0) , 窗口壹无法进入while循环了 。
(2)窗口贰在while循环里面等着 , 看到窗口壹出来了立马就抢先进去了 , 这个时候ticket已经为0了 , 所以它打印第0张票 , 于是ticket变成了-1 , 窗口贰循环结束出来了 , 通过while循环的判断语句(ticket>0) , 窗口贰也无法进入while循环了 。
(3)窗口叁在while循环里面等着 , 看到刚才抢先自己一步进入的窗口贰出来了 , 自己终于可以进去了 , 这个时候ticket已经为-1了 , 所以它打印第-1张票 , 于是ticket变成了-2 , 窗口叁循环结束出来了 , 通过while循环的判断语句(ticket>0) , 窗口叁也无法进入while循环了 。
以上就是第0张票和第-1张票的由来 。
除了这个问题还有一个问题:窗口壹会一直售卖好多张票 。 我们如何让窗口壹卖第一张 , 窗口贰卖第二张 , 窗口叁卖第三张 , 窗口壹卖第四张……这样一直循环依次卖票?
面对这两个问题 , 我们将代码进一步优化:

文章图片
③加一个判断语句:如果票数小于等于0 , 就直接结束循环 , 不执行后面的语句了 。
所以当窗口壹打印完第1张票 , ticket变成了0 。 这时就算窗口贰、窗口叁这两个线程进入了synchronized里面 , 也会有一个if判断语句中的break直接将循环结束掉 。
④让该线程睡眠10毫秒:
Thread有一个静态方法sleep() , sleep是睡眠的意思 , 也就是说窗口壹执行完语句后 , 会让它睡眠10毫秒 , 这样的话窗口贰就能进去执行 , 不然的话根据Java虚拟机的抢占式调度 , 下一次执行语句的可能还是窗口壹 。
以上就是对同步代码块的说明 , 除了同步代码块 , 还有同步方法和Lock锁也可以实现同样的功能 。
三、同步方法和Lock锁
1.同步方法
同步代码块里面的代码 , 我们可以将其提取成一个方法 , 而用synchronized这个关键字来修饰的方法就叫做同步方法:

文章图片
①线程进来遇到同步方法后 , 就只能进去一个线程 , 其它线程得等这个线程执行完后才能进去 。
②同步方法:格式就是在方法声明上加上synchronized这个关键字 。
③如果ticket大于0就打印输出 。
这个同步方法的作用和同步代码块是一样的 。
2.Lock锁
lock是一个接口 , 它提供了比同步代码块和同步方法更广泛的锁定操作 , 更加地强大和体现了面向对象 。
Lock锁也称同步锁 , 加锁与释放锁方法化了 。

文章图片
①Lock是一个接口 , 无法实例化创建对象 , 需要其实现类创建对象 。
推荐阅读
- 程序员■Java程序员必知:HashMap进行put操作会不会引起死循
- 课工场郑州翔天信鸽|JavaScript最常用,java是主流,JetBrains公布编程语言排名
- 猿灯塔|POI Excel,Java架构-Apache
- 【Java】github上标星70.5k,贼火的Java突击手册,全面详细对标阿里P7
- 自学越南语|Redmi 9 智能手机,小米在越南市场推出
- 「编程」后台编程语言互相争执,为何前端公认JavaScript?
- 腾讯@JAVA如何连接数据库
- Java■Java仍然排名第一,但Kotlin不容小视了
- 「javascript」为什么NodeJS是创业公司的首选?了解用于Web开发的NodeJS
- 人世繁华|进行面向对象程序设计深剖,可以一学,大牛带你深入Java核心技术
