Java-初步认识-第十二章-多线程运行图解

一.

为什么会讲述图解,是因为目前DOS给出的一些结果有写颠覆了原有的思想体系。多线程在执行时,cpu切换这执行,不同的内容交叉着出现。但是之前我们讲,一个函数只有执行完了才会弹栈,没执行完不会弹栈。现在通过图解来解释这一切。

以上面的截图来研究图解,我们只研究栈,其他的不做探讨。

以前的内存图解是,main方法进栈,然后涉及调用的方法依次进栈,每执行完一个,出栈一个。最后main方法出栈,井然有序,但是在多线程这里就不能这样操作了。

现在运行方式变了,你只要开启了一条执行路径,它就有了一条单独的执行路径。以前理解为一条马路的话,现在是三条。

主线程只要一开,主线程路径就已经出现了,因为它在调用,或者去执行主函数(这是主线程路径)。在主函数里的代码执行过程中,创建了两个线程(创建和使用是两回事,可以创建后不用)。当主线程读到d1.start()时,就开启了一条路径,这时就多了一条路径。第一条执行路径里的内容是main,第二条执行路径里的内容是run。当主线程继续执行d2.start()的时候,又开启了一条路径,这路径执行的内容还是run。这就相当于它们里面有着自己独立的空间。

main如果调用了调用了其他的方法,就在main的栈区里加栈,就是说你只要是主线程路径上的,就在主线程栈区里加栈,然后进栈弹栈。如果是run()方法调用其他方法的话,就在run栈区里进栈弹栈。同时还给这些线程起了名字,main,Thread-0,Thread-1。每个run方法都有自己所属的线程的栈区。

同时一点都不冲突是因为,每个run方法里面都有一个变量叫x,run方法里有for循环语句的局部变量,(我是觉着x的存在和多个run之间冲不冲突没有什么关系。)

这有三个任务在这执行,一旦有一个任务这里面的代码执行完了,这个任务就结束了。如果是线程0,它调用了一个haha方法,haha方法就要进栈,进的线程0的栈。进了之后,执行结束就出栈了。如果run方法也执行完了,这个线程所执行的任务也就结束了,它这个地方就释放了,这条路径就不需要了。因为线程是要执行代码的,它代

码结束了,线程就没意义存在了。

有没有存在这样一种情况,这三个任务同时在执行,cpu在这三者之间切换。有趣的来了,main线程先结束了,虚拟机结束没?没有,只要还有正在运行的线程,它就会存在。只能说主线程先结束了。

现在再更加扩展的讲述一下,

下面的thread-0和thread-1还在执行,

主线程执行到4/0这句话,就出现了异常。接着这个异常就被抛出了给了jvm默认处理,最后打印在DOS控制台上。输出语句的下面for语句就没再执行,

其他的还在执行,main线程出现了问题,和其他线程没有关系。

(这里甚至打印异常都是分开来的)

多试了几次之后,终于出现了打印的异常信息集中在一起的情况

(但还是有一个run内容出现)

在打印结果的第一行,Exception in thread “main”是之前没讲过的,之前讲述的都是java.lang.ArithmeticException……多出来的第一句意思是异常在线程名为main的里面发生。

我们现在随便编译运行一个不存在的haha

结果显示在主线程中发生,都是一个意思。

现在再进一步地改进,

也就是对run方法的线程也设置成出现异常。

整个编译运行的结果如下,

DOS结果报告了在三个线程上都出现了异常,出现异常后,该线程里的内容就停止运行了。

谁发生问题,谁结束,其他的不影响。

package test2;
/*
 * 创建线程方式一:继承Thread类。
 * 
 * 步骤:
 * 1.定义一个类继承Thread类
 * 2.覆盖Thraed类中的run方法
 * 3.直接创建Thread的子类对象创建线程。
 * 4.调用start方法开启线程并调用线程的任务run方法执行。
 */
class Demo1 extends Thread{
	
	private String name;
	
	Demo1(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+"线程:"+Thread.currentThread().getName());
		}
		
	}

}
class ThreadDemo2 {

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

}

猜你喜欢

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