从现在所学的内容来看,无法创建继承Thread类的对象来实现一百张票三个窗口同时卖。而可以通过创建实现Runnable接口的类对象来达到这个功能。同时考虑到多线程的安全问题,用synchronized同步避免这样的安全隐患。
package 多线程;
/*
* 如何实现一个对象多线程操作。
* 也就是说一百张票让三个窗口卖。
*
*第一步:定义的类实现Runnable接口。
*第二步:覆盖(实现)Runnable接口的run方法
* 原因:将线程要执行的代码存放在run方法中
*第三步:创建Thread类对象
*第四步:创建实现Runnable接口的类对象并把该对象作为实参传给thread类对象的构造器。
* 为什么要把实现Runnable接口的类对象作为参数传给thread类对象的构造器?
* 原因:自定义的run方法所属对象是实现Runnable接口的子类对象,
* 所以要让线程去执行指定对象的run方法。必须明确该run方法所属的对象。
*第五步:调用thread类对象的start方法以开启线程,并且调用run方法。
*
*
*
*实现方式与继承方式的区别
*1,实现方式的好处:避免了单继承的局限性,建议以后要用到多线程功能的时候使用实现方式,最为常用。
*2,继承Thread:线程代码存放在Thread子类对象的run方法中
* 实现Runnable方式:线程代码存放在接口子类对象的run方法中
*
*其实Thread的也是实现了Runnable接口。
*
*而且在这个例子中,实现了要售的票的资源独立共享。
*
*
*多线程的安全问题:
*但线程突然进入睡眠(冻结)状态,失去了cpu执行权,却还有cpu执行资格,
*而当线程回到执行状态时,又有了执行权的时候就可能出现安全隐患。
*详细描述:当多条语句执行一个线程共享数据时,一个线程对多条语句执行了一部分,
* 还没有执行完,另一个线程就参与进来了,导致共享数据的错误。
*
*解决办法——当执行多条代码,进行共享数据的访问时,只能让一条线程执行完,其他线程进不来这一块代码。
*
*即同步 synchronized(对象){需要被同步的代码块。}
*那怎么判断哪些是要被执行的代码块呢?
*谁用到共享数据,就同步谁~
*
*
*
*可以通过Thread.sleep(time)模拟。 time以毫秒为单位。
*而sleep()方法会声明InterruptException异常。必须处理,不能抛。(但是为什么呢?)
*/
public class Tickets implements Runnable//extends Thread
{
//创建三个售票窗口,卖一百张票。如何实现,用static
//但是一般不定义静态,因为它的生命周期太长?
private int sumOfTickets = 100;
//
//
// public TicketWindow(String WinNum)
// {
// super(WinNum);
// }
Object obj =new Object();
public void run()
{
while(true)
{
synchronized(obj)
{
if(sumOfTickets >=0)
{
//为什么这里可以调用Thread的方法呢?
//因为复写了接口的run方法,抛不出去,一抛就是错。
//因为是实现了接口,接口的run方法原来就没有抛异常,所以覆盖的方法也不能抛异常,只能内部处理。
try{Thread.sleep(60);} catch(Exception e){}
//因为把Tickets类对象传给了Thread线程类对象,所以这里就可以
//调用线程的名字。
System.out.println(Thread.currentThread().getName()+
"卖完一张票了,还剩"+sumOfTickets--);
}
}
}
}
}
package 多线程;
public class TicketDemo {
public static void main(String[] args)
{
Tickets sum = new Tickets();
Thread Window1 = new Thread(sum);
Thread Window2 = new Thread(sum);
Thread Window3 = new Thread(sum);
Window1.start();
Window2.start();
Window3.start();
// 无法实现三个窗口卖同一百张票
// Thread W1 =new TicketWindow("售票窗口1");
// Thread W2 =new TicketWindow("售票窗口2");
// Thread W3 =new TicketWindow("售票窗口3");
// W1.start();//线程状态只需要一次启动,不可以多次使用start()方法。
// W2.start();
// W3.start();
//
}
}