多线程01——线程的启动有规律但执行没有规律

多线程是指在同一个进程中有多个顺序流同时执行。一个应用程序由一个或多个进程组成。

应用程序是Application,比如迅雷这款软件;进程是Process,迅雷至少包括了界面进程和下载进程;线程是Thread,迅雷的下载进程里面有多个线程一起工作,才能完成下载功能。

在并发环境中,默认条件下多线程里的方法的执行顺序是随机无序的,并不是按照比如线程对象的创建顺序、start()方法的先后执行顺序而先后顺序执行。比如Thread-0和Thread-1执行一个相同的方法,Thread-0这个线程虽然是先创建的,但其内部的方法不一定最先完成。

注意,这里的随机无序指的是线程里的方法。线程的创建是有序的,谁先执行start()方法谁就先被创建。即启动顺序不等于执行顺序。
因为执行一个线程时,线程并不会立即执行,而是等待CPU的资源调度,CPU能调度哪个线程,是与底层物理硬件相关的,外界无法控制。
程序员可以控制的是程序是否抢占CPU资源。

Java里面多线程要执行的代码要放在run()方法内部,run()方法的方法体也被称为线程体。

更为通俗的理解是将run()方法作为主线程外其它线程的入口方法,即run()方法之于其它线程的地位相当于主线程的main()方法。

简单的开启多线程方式有两种:继承Thread类、实现Runnable接口。


/**
 * 实现Runnable接口
 * @author Zhang
 *
 */
public class MyRunThread implements Runnable{
	//run()方法相当于主线程中的main方法,run()是该线程入口
	@Override
	public void run() {
		System.out.println("实现接口线程名称>>"+Thread.currentThread().getName());
		otherThreadMethod();
	}
	
	public static void otherThreadMethod() {
		for(int i=1;i<=5;i++) {
			System.out.println("实现Runnable>>"+Thread.currentThread().getName()+":数值>>"+i);
		}
	}
	
}
/**
 * 继承Thread类
 * @author Zhang
 *
 */
public class MyThread extends Thread{
	@Override
	public void run() {
		System.out.println("继承Thread线程名称>>"+Thread.currentThread().getName());
		otherMethod();
	}
	public void otherMethod() {
		for(int i=1;i<=5;i++) {		
			System.out.println("继承Thread>>"+Thread.currentThread().getName()+":数值>>"+i);
		}
	}
}

对以上多线程类进行启动,启动的标准是看是否调用了start()方法,因为主线程是必须启动且先启动,其它线程的启动看start()方法的先后顺序,所以下面的线程启动顺序一定是主线程、继承Thread的线程、实现接口的两个线程,但是各个线程之间方法的执行是无序的。

public class Test {
	//主方法本身所在的是主线程
	public static void main(String[] args) {
		System.out.println("主线程名称>>"+Thread.currentThread().getName());
		//创建Runnable实现类对象
		MyRunThread runThread=new MyRunThread();
		//创建继承Thread类的多线程对象
		Thread thread=new MyThread();
		//Runnable实现类传入Thread
		Thread runTthread1=new Thread(runThread);
		Thread runThread2=new Thread(runThread);			
		//启动一个线程
		thread.start();
		//启动一个线程
		runTthread1.start();
		//启动一个线程
		runThread2.start();
		
		//执行主线程中方法
		mainMethod();
		
	}
	
	public static void mainMethod() {
		for(int i=1;i<5;i++) {
			System.out.println("主线程>>"+Thread.currentThread().getName()+":数值>>"+i);
		}
	} 
	
}

结果:

主线程名称>>main
主线程>>main:数值>>1
主线程>>main:数值>>2
实现接口线程名称>>Thread-2
实现Runnable>>Thread-2:数值>>1
实现Runnable>>Thread-2:数值>>2
实现Runnable>>Thread-2:数值>>3
实现Runnable>>Thread-2:数值>>4
实现Runnable>>Thread-2:数值>>5
主线程>>main:数值>>3
实现接口线程名称>>Thread-1
实现Runnable>>Thread-1:数值>>1
继承Thread线程名称>>Thread-0
实现Runnable>>Thread-1:数值>>2
主线程>>main:数值>>4
实现Runnable>>Thread-1:数值>>3
继承Thread>>Thread-0:数值>>1
实现Runnable>>Thread-1:数值>>4
继承Thread>>Thread-0:数值>>2
实现Runnable>>Thread-1:数值>>5
继承Thread>>Thread-0:数值>>3
继承Thread>>Thread-0:数值>>4
继承Thread>>Thread-0:数值>>5

具体而言,主线程内子线程start()后并不一定立即执行子线程内的run()方法。

public class MyRunThread implements Runnable{
	//run()方法相当于主线程中的main方法,run()是该线程入口
	@Override
	public void run() {
		//获取当前线程名称
		System.out.println("线程类内,子线程名称:"+Thread.currentThread().getName());
		otherThreadMethod();
	}
	
	public static void otherThreadMethod() {
		for(int i=1;i<=5;i++) {
			System.out.println(Thread.currentThread().getName()+":数值>>"+i);
		}
	}
	
}

//测试类

public class Test {
	
	public static void main(String[] args) {
		//获取当前线程名称
		System.out.println("主线程名称>>"+Thread.currentThread().getName());
		
		//创建一个子线程
		Runnable runThread=new MyRunThread();
		Thread thread1=new Thread(runThread);

		//启动1个子线程
		thread1.start();

		//获取子线程的默认名称
		System.out.println("子线程名称>>"+thread1.getName());
		//设置子线程名称
		thread1.setName("子线程1");
		//执行主线程中方法
		mainMethod();
	}
	
	public static void mainMethod() {
		for(int i=1;i<5;i++) {
			System.out.println(Thread.currentThread().getName()+":数值>>"+i);
		}
	} 
	
}

结果如下,可以发现run()方法执行的获取子线程名称是在主方法setName后的结果,所以证实了start()之后并不一定会立即执行run()方法,因为主线程的资源让出,子线程才有可能执行。


主线程名称>>main
子线程名称>>Thread-0
main:数值>>1
main:数值>>2
线程类内,子线程名称:子线程1
子线程1:数值>>1
子线程1:数值>>2
子线程1:数值>>3
子线程1:数值>>4
子线程1:数值>>5
main:数值>>3
main:数值>>4

 

おすすめ

転載: blog.csdn.net/JWbonze/article/details/90031325