zoukankan      html  css  js  c++  java
  • 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接口的存在。

  • 相关阅读:
    洛谷 P4001 [ICPC-Beijing 2006]狼抓兔子
    杂题20201201
    杂题20210103
    杂题20201010
    杂题20200928
    ACL1 Contest 1 简要题解
    杂题20200906
    杂题20200623
    USACO2020DEC Gold/Platinum 解题报告
    CSP-S2020游记
  • 原文地址:https://www.cnblogs.com/wsw-bk/p/8028703.html
Copyright © 2011-2022 走看看