目录
线程理解与调度
理解线程
- 线程是独立的,它代表独立的执行空间。Thread是java中用来表示线程的类。要建立线程就要创建Thread。
- 每一个程序都会启动一个主线程--main(),并且main方法会放在自己的执行空间的最开始处。这些主线程的启动是由java虚拟机及逆行处理,而程序员自己负责自己建立的线程。如下图所示:
- Thread是一个表示线程的类,他又启动线程,连接线程,让线程闲置等的方法。如图:
- 线程的执行顺序是什么?答:我们可以这么理解线程的执行空间。当有超过一个以上的执行空间时,看起来会像好多事情同时发生。其实只有真正的多处理器系统才会能够同时执行好几件事,但使用java线程可以让它看起来好像在同时执行中。也就是说java可以使执行动作在执行空间内非常快速的来回交换,因此你会感觉到每一个任务都在执行。执行动作的交换就是执行不同线程的执行空间的最上面的方法。我们写一个例子来理解线程之间的切换。
//(1) java虚拟机调用main 这个时候主线程启动,主线程处于活跃的状态。
public static void main (String [] args){
...
}
//(2)main启动新的线程,新的线程启动期间,main线程会暂时停止执行。
Eunnable r=new MyThreadJob();
Thread t=new Thread(r);
t.start();
Dog d=new Dog();
//(3)java虚拟机会在线程与原来的主线程间切换,知道两者都执行完毕为止。
- 如何启动新的线程?第一个使用Thread类,第二个实现Runnable接口来建立给Thread运行的任务。
//这里介绍第二种方法 public class MyRunnbale implements Runnables{ public void run(){ go(); ///只有一个方法需要实现,并且这个方法没有参数,只需要把运行的程序放在这里 } } class ThreadTester{ public static void main(String [] args){ Runnable threadJob=new MyRunnable(); //将Runnable的实例传给Thread的构造函数 Thread myThread=new Thread(threadJob); myThread.start(); //必须要调用start方法才会让线程开始执行,不然在此之前,它只是一个Thread的实例,并不是真正的线程。 System.out.println("线程启动"); } }
线程调度器
- 线程调度器会决定哪个线程从等待状况中被挑选出来运行,以及何时把哪个线程送回到等待被执行的状态,它会决定某个线程运行多久,线程被踢出时它也会指定线程要回去等待下一个机会或者是暂时的堵塞。
- 我们通过一个例子,来分析线程调度的运行过程。
package com.gy.universities.sdkTest;
/**
* @program: universities
* @description: ${description}
* @author: ShiDunKai
* @create: 2019-05-03 19:23
**/
public class MyRunnable implements Runnable {
@Override
public void run() {
go();
}
public void go(){
doMore();
}
public void doMore(){
System.out.println("top o' the stack");
}
}
package com.gy.universities.sdkTest;
/**
* @program: universities
* @description: ${description}
* @author: ShiDunKai
* @create: 2019-05-03 21:54
**/
public class ThreadTestDrive {
public static void main(String[] args) {
Runnable threadJob=new MyRunnable();
Thread myThread=new Thread(threadJob);
myThread.start();
System.out.println("back in main");
}
}
- 它的执行结果会有两种情况:
back in main top o' the stack 和 top o' the stack back in main //这说明我们线程此时的两种运行状态 //1 main启动新的线程,调度器把主线程搁置,执行新的线程,新的线程结束后,主线程恢复执行。 //2 main启动新的线程,调度器把主线程搁置,调度器执行新的线程到go()回到主线程,列出信息后又回到新线程,执行完毕doMore方法。
- 那我们怎么简单的调整循序呢?很简单,使用sleep可以让程序可以预测。
package com.gy.universities.sdkTest;
/**
* @program: universities
* @description: ${description}
* @author: ShiDunKai
* @create: 2019-05-03 19:23
**/
public class MyRunnable implements Runnable {
@Override
public void run() {
go();
}
public void go(){
try {
Thread.sleep(2000); //这里让线程离开执行中的状态,休息2秒
}catch (InterruptedException ex){
ex.printStackTrace();
}
doMore();
}
public void doMore(){
System.out.println("top o' the stack");
}
}
- 结果就变成可控
接下来我们一起研究下线程产生的并发性问题。