生活中其实有很多多线程的例子,比如火车站售票就是一个例子。我们先来分析一下,
(1)首先要有火车票的总数量,并且每卖出一张火车票,总量就减一
(2)当火车票的数量小于1的时候,就停止售票
(3)使用多线程模拟各个窗口进行售票
(4)当火车票售完后,火车站也同样欢迎我们
下来,我们代码来实现火车站售票实例
public class MyThread implements Runnable {
int tickets=5;
@Override
public void run() {
while(true) {
if(tickets>0) {
try {
Thread.sleep(100); //让当前线程睡一会儿
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+": "+tickets--);
}
}
}
}
public class ThreadDemo {
public static void main(String[] args) {
//创建线程实例
MyThread mt=new MyThread();
Thread t=new Thread(mt);
t.setName("窗口一");
t.start();
//创建线程实例
Thread t2=new Thread(mt);
t2.setName("窗口二"); //修改线程名字
t2.start(); //启动线程
Thread t3=new Thread(mt);
t3.setName("窗口三"); //修改线程名字
t3.start(); //启动线程
}
}
/*
窗口三: 5
窗口一: 4
窗口二: 3
窗口三: 2
窗口一: 1
窗口二: 0
窗口三: -1
*/
观察输出结果,居然出现了-1!这不是我们想要的结果,为什么呢?因为在run()方法中,我们使用sleep()方法让线程睡了一会儿,就出现了-1这个结果,那为什么呢?
我们可以这样理解,假设此时就只剩下一张票没有卖出去了,
这时t1进来了,一看有票准备开始售票,但是他突然肚子疼就去上厕所了。
这个时候t2进来了,一看有票准备开始售票,但是他突然也肚子疼就去上厕所了。
其实这个时候相当于t1、t2已经进入if这个判断语句了。
过了一会儿t1上完厕所回来了,开始售票,这个时候所有的票已经卖完了,tickets=0。
这个时候t2也上完厕所回来了,但是他不知道票卖完了(因为他早都进入if语句里面了),然后开始售票,这个时候tickets=-1就出现了我们上面的结果了。
所以为了解决这个问题,我们引入了同步机制
synchronized: 关键字,同步(锁),可以修饰代码块和方法,一旦被某个线程访问,则直接锁住,其它线程不能访问
同步代码块
synchronized(锁){
}
注意:锁对象需要被所有线程共享
接着上面的例子,我们给其上锁
public class MyThread implements Runnable {
int tickets=5;
Object obj=new Object(); //锁对象
@Override
public void run() {
while(true) {
synchronized(obj){ //上锁
if(tickets>0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+": "+tickets--);
}
}
}
}
}
/*
窗口二: 5
窗口二: 4
窗口一: 3
窗口一: 2
窗口三: 1
*/
我们发现这个时候的输出结果是正确的。但是我们在运行的过程中发现运行速度没有之前快,这是因为加了锁以后每次都要进行开锁、关锁,所以执行速度变慢了。