JAVA-初步认识-第十三章-多线程(卖票示例-重叙)

一.

需求:简单卖票程序。

怎么卖:多个窗口卖票。

一号窗口在卖票的时候,二号窗口,三号窗口也在卖票,这是同时在操作。也就是多线程。

Ticket类中的卖票代码必须要被多个线程所执行。

需求是卖票,那么名词就是票,对票进行类的描述,怎么卖票自己知道。因此,Ticket类里面必须要定义卖的方法。

由于是多个窗口卖,所以该方法是多线程。所以,要将代码存放在run方法当中,而且要继承Thread类,覆盖run方法。

只有特殊书写的run方法,才是多线程任务,不然仅是一个名为run的方法

接着对程序进行填充,票的数目在变化,定义为变量。其实类名为Ticket不太合适,类名为卖票更为合适,我觉着

这里面关于循环卖票的语句,我还不理解。

Ticket类在创建对象时,就是在创建多线程。创建了四个对象,就是开了四条线程。接着调用start方法,就是在启动运行。

从运行的结果来看,票都卖完了。现在想要看是谁卖的。

对程序进行修改,

截图中的currentThread().getName方法,没有之前的Thread. ,其实这个方法是父类方法,继承过来属于自己也有。

如果用Thread. currentThread().getName也行,但是它背后的原理是什么呢?父类使用方法,输出的是子类的数据,难道和继承有关系?

DOS结果显示,四个线程都在卖票,但是每个线程都有卖1号票(举个例子)。这相当于四个窗口卖了四百张票。

问题出现在,创建一个对象,里面就有一百张票。怎么解决?(其实,我首先想到的是,为什么会出现这样的问题?)

让四个对象共享一百张票,想到了静态了。

只有确切的理解了静态的用法,才能知道用静态靠谱。

添加了static之后,DOS的结果正确了,只卖出了一百张票。这又带来一个问题,为什么1号票在2,3号票之前出来?

因为程序在运行的时候,虚拟机除了在打印票之外,它又在调用另外一个程序DOS命令行。DOS命令行如果是单核cpu的话,

这块打印的结果1应该是最后一个。而要是双核cpu的话,这个程序就会有点变化了。1的票有可能已经出来的,先被打印了。2,3后被打印了。打印的结果是双核造成的。

但是我们一般不定义静态,为什么?它的生命周期太长,那么怎么来解决。

一个对象是一百张票,那就定义一个对象。跑四次就好了。

DOS结果显示为一个窗口,但是有异常的存在。Thread-0

报错为无效线程状态异常,这是为什么?已经从创建状态到运动状态,连续开启运动就是无效的。

线程状态出现了问题,已经运行的线程不需要再次开启。

那么该如何解决这个问题,(第一种创建方式已经不靠谱了)。接下来看看第二种创建方式。

二.

在java.lang包中除了类之外,还有接口,

接口中就有Runable,Runable的意思就是可运行的。这接口非常的简单就一个方法。

(通过其他线程来执行自己需要执行的内容,就用Runable,这是我的理解)

操作中,自定义类中必须有一个run()方法,来覆盖被实现的Runable接口中的run()方法。(接口是继承的特殊化)

主函数中首先创建了自定义类的对象t,要明确的是这个t对象不是线程。因为它和Thread类没有关系,是不是线程由Thread类的继承体系说了算。

现在要通过多线程来并发执行,所以必须要创建一个线程,即创建线程Thread类的对象,Thread t1=new Thread();由于是四个窗口在卖票,因此要创建四个不同的线程。线程创建完要运行的话,必须通过线程对象调用start()方法。

编译,运行的结果如下,

DOS结果显示,没有运行我们书写的程序,(我们的程序是要输出100张票)。

这里就要分析,程序中的start(),它会开启线程没有错,它会调用线程的run()方法,但是它调用的是Thread类中的run方法。这个run方法里没有卖票。那就错了。

现在的问题就是怎么让t1~t4的start()调用Ticket类中的run方法呢?

Ticket类中的run方法属于谁?它是非静态的,需要被对象调用。对象是谁?就是Ticket类的对象,Ticket对象中的run方法要被Thread类的对象执行,它们二者之间是不是要联系起来,这是第一个问题。

第二个问题,创建线程的目的是不是为了运行我们指定的代码?代码在对象t里面呢?怎么能够让这个对象和线程有关系呢?

在创建线程对象时,就应该明确要运行什么代码。第一种创建线程方式中,子类继承了父类,创建子类对象时,就已经明确了线程要运行的内容。但是这里是第二种方式,创建的父类对象,怎么明确线程要执行的对象呢?

在构造对象时,它有一个构造方法比较特殊。能够接收Runable类型接口的对象,为什么要实现Runable接口?因为Thread类认识Runable接口。也就是说在new线程对象的同时,就指定run方法所属对象。

结果显示,四个线程已经跑起来了,同时打印的结果显示,正好输出一百张票。几个线程都有在卖票。

第五步,调用Runable接口子类的run方法值得研究。

学生继承了人的同时,还可以实现接口。这就是接口的好处,对外提供了功能性的扩展,学生具备了人当中的一些特性,并又扩展了自己的功能。学生还能被多线程所操作。

java工程师在设计的时候,你日后会出现什么样接口子类,它是不知道的,所以它用了多态的形式,在这建立了接口的引用。

只要是符合实现接口的规则,都可以参与多线程执行。Thread类本身也实现Runable,为什么?Runable接口的定义,其实就是在确立线程要运行代码所存放的位置就是run方法。

这就相当于说,能够多线程执行就是因为,Runable接口的存在。

原文地址:https://www.cnblogs.com/wsw-bk/p/8028703.html