进程和线程

线程依赖于进程而存在

进程:正在运行的程序 1、是系统进行资源分配和调用的独立单位 2、每一个进程都有它自己的内存空间和系统资源

线程:是进程中的单个顺序控制流,是一条执行路径 1、单线程指的是一个进程如果只有一条执行路径,则称为单线程程序 2、多线程指的是一个进程如果只有多条执行路径,则称为多线程程序 注意:进程是计算机中资源分配的最小单位,而线程是进程的执行单位。一个进程可以包含多个线程 举例:记事本程序是单线程,扫雷程序是多线程

 

继承Thread类的方式实现多线程

Thread类在java.lang包下。该类是具体类,继承自Object,实现自Runnable接口

线程是程序中执行的线程,即Thread类可以理解为是一个线程。Java虚拟机允许应用程序同时运行多个执行线程

线程是如何创建出来的呢,有两种方式可以创建新的执行线程。如下

方式一:继承Thread类,步骤如下 1、定义一个类MyThread继承Thread类 2、在MyThread类中重写run()方法 3、创建MyThread类的对象 4、启动线程

Thread类里面有一个start方法,作用是使此线程开始执行; Java虚拟机调用此线程的run方法

为什么要重写run方法,原因:因为run()是用来封装被线程执行的代码

run()方法和start()方法的区别: 1、run():封装线程执行的代码,直接调用,相当于普通方法的调用 2、start():做了两件事,第一件事是启动线程,第二件事是由JVM调用此线程的run()方法

 

继承Thread类来实现多线程的练习

 

设置和获取线程名称

Thread类中设置和获取线程名称的方法 1、void setName(String name): 将此线程的名称更改为等于参数name 2、String getName():返回此线程的名称 3、通过构造方法也可以设置线程名称

如何获取main方法所在的线程名称,如下 第一步:public static Thread currentThread():返回当前正在执行的线程对象 第二步:Thread.currentThread().getName():用线程对象来调用getName才能获取到线程的名称

 

设置和获取线程名称的练习

 

线程优先级

线程调度:线程有两种调度模型 1、分时调度模型:所有线程轮流使用CPU的使用权,平均分配每个线程占用CPU的时间片 2、抢占式调度模型:优先让优先级高的线程使用CPU,如果线程的优先级相同,那么会随机选择一个,优先级高的线程获取的CPU时间片相对多一些

Java使用的是抢占式调度模型

假如计算机只有一个CPU,那么CPU在某一时刻只能执行一条指令,线程只有得到CPU时间片,也就是使用权,才可以执行指令。 所有说多线程程序的执行是有随机性,因为谁抢到CPU的使用权是不一定的

思考: 我们能不能控制线程的优先级呢。答案是能,如下 Thread类中设置和获取线程优先级的方法: 1、public final int getPriority() 作用是返回此线程的优先级 2、public final void setPriority(int newPriority) 作用是更改此线程的优先级

结论: 1、线程默认优先级是5,线程优先级的范围是1~10 2、线程优先级高仅仅表示线程获取的CPU时间片的几率高。但是要在次数比较多,或者多次运行的时候才能看到你想要的效果

 

线程优先级的练习

 

线程控制_sleep

方法名说明
static void sleep(long millis)使当前正在执行的线程停留(暂停执行)指定的毫秒数
void join()等待这个线程死亡
void setDaemon(boolean on)将此线程标记为守护线程,当运行的线程都是守护线程时,Java虚拟机将退出

线程控制_sleep的练习

 

线程控制_join

方法名说明
static void sleep(long millis)使当前正在执行的线程停留(暂停执行)指定的毫秒数
void join()等待这个线程死亡
void setDaemon(boolean on)将此线程标记为守护线程,当运行的线程都是守护线程时,Java虚拟机将退出

 

 

线程控制_join的练习

 

线程控制_setDaemon

方法名说明
static void sleep(long millis)使当前正在执行的线程停留(暂停执行)指定的毫秒数
void join()等待这个线程死亡
void setDaemon(boolean on)将此线程标记为守护线程,当运行的线程都是守护线程时,Java虚拟机将退出

 

线程控制_setDaemon的练习

 

线程的生命周期

生命周期如下:

1、创建线程对象 2、调用start方法,此时线程开始启动 3、线程进入就绪状态,即有执行资格却没有执行权。原因:线程启动后不会马上就抢到CPU的执行权 4、抢到CPU的执行权 5、线程进入运行状态,即有执行资格也有执行权 6、当run()结束或调用stop方法,线程就会死亡

总结:新建、就绪、运行、死亡

注意:一个线程在运行状态时如果被其他线程抢走CPU的执行权,那这个线程就会回到就绪状态,即这个线程会继续抢占CPU的执行权

注意:一个线程在运行状态,突然调用了sleep方法,那这个线程就会进入阻塞状态,即没有执行资格且没有执行权。只有等待到sleep方法结束,这个线程会回到就绪状态,即有执行资格却没有执行权

 

实现Runnable接口的方式实现多线程

创建线程有两种方式,我们之前在ch21的a_2_0~a_8_0学习了通过继承Thread类的方式来创建线程。 现在,我们来学习另一种创建线程的方式,如下

即定义一个实现Runnable接口的类,接着在这个定义的类里面重写run方法和分配类的实例 最后把这个定义的类的对象作为Thread构造方法的参数传递并启动线程

具体步骤如下: 1、定义一个类MyRunnable实现Runnable接口 2、在MyRunnable类中重写run方法 3、创建MyRunnable类的对象 4、创建Thread类的对象,把MyRunnable对象作为构造方法的参数 5、启动线程

注意上面的第四步创建创建Thread类的对象需要用到Thread类的构造方法,如下 Thread(Runnable target) 分配新的Thread对象

多线程的实现方案有两种: 1、继承Thread类 2、实现Runnable接口

创建接口的两种方式,我们这节课学的'通过实现Runnable接口'方式,相比之前学的'继承Thread类'方式有如下优点: 1、避免了Java单继承的局限性 2、适合多个相同程序的代码去处理同一个资源的情况,把线程和程序的代码、数据有效分离,较好的体现了面向对象的设计思想

 

实现Runnable接口来实现多线程的练习