一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第19天,点击查看活动详情。
Java中的多线程编程
需要:
(1)掌握多线程编程的特点;
(2)了解线程的调度和执行过程;
(3)掌握资源共享访问的实现方法。
编写一个Java多线程程序,模拟实现火车站售票系统:
需求分析:
假如火车站要有20张火车票要卖出,现在有5个售票点同时售票,用5个线程模拟这5个售票点的售票情况。
实现思路
(1)新建类SaleTicket实现接口Runnable具备多线程操作的能力
(2)实现run()方法编写线程体,使用同步代码块或同步方法提高程序的安全性
(3)编写SaleTicketDemo类进行测试
这个时候简单的实现会出现问题,比如:一张票被多个窗口卖,或者最后卖出了超过二十张票的情况等,这就是线程不安全。
如何解决线程安全问题呢?
要想解决问题,就要知道哪些原因会导致出问题:(而且这些原因也是以后我们判断一个程序是否会有线程安全问题的标准)
A:是否是多线程环境
B:是否有共享数据
C:是否有多条语句操作共享数据
我们来回想一下我们的程序有没有上面的问题呢?
A:是否是多线程环境 是
B:是否有共享数据 是
C:是否有多条语句操作共享数据 是
由此可见我们的程序出现问题是正常的,因为它满足出问题的条件。
接下来才是我们要想想如何解决问题呢?
A和B的问题我们改变不了,我们只能想办法去把C改变一下。
思想:
把多条语句操作共享数据的代码给包成一个整体,让某个线程在执行的时候,别人不能来执行。
问题是我们不知道怎么包啊?其实我也不知道,但是Java给我们提供了:同步机制。
同步代码块:
synchronized(对象){
需要同步的代码;
}
A:对象是什么呢?
我们可以随便创建一个对象试试。
B:需要同步的代码是哪些呢?
把多条语句操作共享数据的代码的部分给包起来
注意:
同步可以解决安全问题的根本原因就在那个对象上。该对象如同锁的功能。
多个线程必须是同一把锁。
A:同步代码块的锁对象是谁呢?
任意对象。
B:同步方法的格式及锁对象问题?
把同步关键字加在方法上。
同步方法的锁是谁呢?
this
虽然可以理解同步代码块和同步方法的锁对象问题,但是并没有直接看到在哪里加上了锁,在哪里释放了锁,
为了更清晰的表达如何加锁和释放锁,JDK5以后提供了一个新的锁对象Lock。
Lock:
void lock(): 获取锁。
void unlock():释放锁。
ReentrantLock是Lock的实现类.
核心代码:
while(total > 0) {
synchronized(this) {
if(total > 0){
……
}
}
}
参考解决方案:
while (total > 0) {
synchronized (this) {
if (total > 0) {
try{
Thread.sleep(500);
} catch(InterruptedException e) {
e.printStackTrace();
}
count++; // 票号++
total--;// 总数减少
// 输出当前的售票窗口和票号
System.out.println(Thread.currentThread().getName()+ "\t当前票号:" + count);
}
}
}