JAVA-初步认识-第十二章-多线程创建方式一继承

 一.

既然是创建线程,那么线程应该怎么创建?在没有学习java之前,这些程序是谁在操作执行的呢?是由我们所在的操作系统来完成的。Windows里面有个任务管理器,它来管理这些任务,它来创建这些进程,并来创建进程中所用的线程。是由系统来完成的,我们无法直接使用系统来帮我们做这件事情。解决问题的时候,首先想到的是java中是否有给我们提供能解决该问题的对象,尤其是线程还走了系统。你不玩java,它没有多线程,因为windows具备这能力,它在帮你做这个分配呢。我们是做不了的,我们就想说java是否也有这样的对象,来找底层做这件事情,并把对象暴露出来给我们用呢。我们做事情解决问题,要先找对象。(找到线程对象么?是的,线程对象来做执行动作,就不需要我们来操作了)

那么这对象是谁呢?我们到java的API文档里来查阅一下。在java的核心包里面,java.lang(java语言包)。为什么要找核心包,是因为虚拟机一启动,就带着多线程,所以对象就在这呢(控制多线程的对象在核心包里,因为从这发起的)。Java.lang包里有这么一个对象thread

这个线程,我们知道有这么一个thread类(原来thread类就代表着线程)。咋创建呢?

学习对象的时候吧,如果没有人教授,就要阅读API文档。

在API文档中,还有一个使用thread方法的示例,里面有构造函数和复写的run方法。(虽然有两种方法,但是只介绍了一种创建执行路径方法)

(梳理一下,要想创建新的线程,先要继承thread类,然后复写其中

的run方法)

为什么要重写run方法呢?

这里要介绍创建线程的第一种方式,

继承thread类是理解的(继承是为了具备父类的特性-创建线程),为什么要覆盖run方法?

Thread类中的组成如下,有构造器,

同时thread类并不是抽象的,(说明thread可以创建对象),它能new对象。问题解决了,java已经给我们提供了thread类,而且创建其对象就是线程(这句话怎么得出来的?因为thread对象就是线程),这就可以了,为什么要依据API文档中的继承,覆盖什么的。

创建thread对象,就是创建线程对象。

创建线程的目的是什么?创建线程的目的是为了开启一条执行路径,开启执行路径的目的是为了什么?是为了让一部分代码和其他代码同时运行,而这部分代码我们称之为任务。这就是刚才一直在分析的特点。

任务是一段代码,这段代码要被封装了才能用。这个封装体就是run方法。这个才是thread类里面有run方法的原因。

有人说,直接new对象,调用run方法就完事儿了。这么讲没错,但是你那run方法里面的任务是我需要的吗?(这就是复写的原因)

我们开启线程的目的是为了运行我们定义的任务,你有任务函数,我有任务内容,该怎么办?就应该继承你,并覆盖你,把我的内容写到你的run方法里面去。这就是我们为什么继承并复写run方法的原因。

(用子类继承thread类,就是为了覆盖父类中的run方法,来运行自己想要运行的内容)

因此,就不再做新建thread对象的操作了,而是继承操作了。

根据之前的例子,卡在循环这,我们必须要重开一个线程运行循环语句。本节讲述到现在,就为了介绍如何将循环语句,引入新建的线程。

(这是另一种形式的循环语句引入run方法)

到目前为止,覆盖完了。第三步就是创建线程对象,搞一个类,继承thread,thread是线程,继承它,我也是线程(继承它的所有特点)。

→我知道了,为什么要创建子类对象了,光有继承的子类,覆盖的run方法,没有用。必须有对象才能调用方法运行。

现在修改了主程序中的代码,对象在调用run方法。这个时候,无论是d1还是d2都是线程,

编译运行的结果,依旧是之前的那样。

为什么会这样呢?为什么还是主线程在这行呢?(怎么知道是主线程执行的呢?)试想一下,如果真的是有两个线程被创建了,它们要如果运行起来了,就意味着d1和d2运行run方法,这两个有可能随机。

现在修改一下程序,在两个循环之间加上输出语句。看看他们是不是有序的。

结果显示,两个循环输出还是固定有序的。说明到目前为止,还是只有一个主线程在执行。为什么呢?线程这类事物比较特殊,创建完以后,你去调用这个run方法,其实跟我们之前创建对象调用方法一点区别也没有。这是一个标准的常规调用方式,如果你想要使用线程做这件事,你得到线程类当中去找方法。

在示例的后面,还有一句话,然后….创建并启动一个线程。这个thread继承子类对象创建了不好使,还得启动。

谁做开启动作,start方法。怎么开启,线程自己最清楚(所以到线程类中寻找相应的方法),

用手工调用run方法吗?不用,直接start就可以了。

Start方法做了两件事儿,一是开启线程,二是调用run方法,告诉虚拟机调用该方法。

经过前面的实例讲解,调用run和调用start有什么区别?

这会运行的结果终于符合我们原先的设想了。Cpu在做随机的切换,(因此两个结果是随机的),我们这里有三个线程(两个循环线程,将主线程抛开),主线程和自己开启的俩。Cpu在三个线程间快速的做着切换,切到谁运行谁,所以是随机的。结果怎么打印,怎么输出是cpu说了算。

package test2;
/*
 * 创建线程方式一:继承Thread类。
 * 
 * 步骤:
 * 1.定义一个类继承Thread类
 * 2.覆盖Thraed类中的run方法
 * 3.直接创建Thread的子类对象创建线程。
 * 4.调用start方法开启线程并调用线程的任务run方法执行。
 */
class Demo extends Thread{
	
	private String name;
	
	Demo(String name) {
		// TODO Auto-generated constructor stub
		this.name = name;
	}
	
	public void run() {
		for (int i = 0; i < 10; i++) {
		
		    System.out.println(name+"...x"+i);
		}
		
	}

}
class ThreadDemo2 {

	public static void main(String[] args) {
		/*
		 创建线程的目的是为了开启一条执行路径,去运行指定的代码和其他代码实现同时运行。
		 而运行的指定代码就是这个执行路径的任务。
		 
		jvm创建的主线程的任务都定义在了主函数中
		 
		 而自定义的线程它的任务在哪儿呢?
		 Thread类用于描述线程,线程需要任务的。所以Thraed类也对任务的描述。
		 这个任务就是通过Thread类中的run方法来体现。也就是说,run方法就是封装自定义线程运行任务的函数。
		 
		 run方法中定义就是线程要运行的任务代码、
		 开启线程是为了运行指定代码,所以只有继承Thread类,并复写run方法。
		 将运行的代码定义在run方法即可。
		 */
		Demo d1 = new Demo("旺财");
		Demo d2 = new Demo("小强");
		
		d1.start();//开启线程,调用run方法。
		d2.start();//
		
	}

}

在转载的基础上,加上了自己的内容。


猜你喜欢

转载自blog.csdn.net/fighting_future/article/details/80256476