写在前面
这篇随笔就简单记录一下《Java入门经典》第12章——“一心二用”的多线程技术中看到的一些知识点。
进程与线程
一个进程是一个包含自身执行地址的程序,通常将正在运行的程序成为进程。
一个进程内部可以执行多任务,将进程内部的任务成为线程。线程是进程中的实体,一个进程可以拥有多个线程。
说道线程与进程可以参考:
一个线程是进程中执行的一个流程,一个程序中可能同时进行多个不同的线程,每一个线程可以执行一小段时间,由于多个线程之间切换速度快,所以就好像是程序同时执行多件事情一样。
线程必须拥有父进程,系统没有为线程分配资源,他与进程中的其他线程共享该进程的系统资源。
所谓单线程,是一个程序内某个结构化的流程控制,有时候被称为“执行环境”或“轻量级程序”,它是由上而下的结构化程序。
创建线程
Java中,线程也是一种对象,目前有两种方法创建线程:
- 继承Thread类;
- 实现Runnable接口。
1.继承Thread类
Thread类是java.lang中的一个类,从这个类中实例化的对象代表线程。Thread类的两个常用的构造方法如下:
public Thread(String thread Name);
public Thread();
//OR
public class ThreadTest extends Thread{
//...
}
完成线程真正功能的代码放在类的run()方法中,当一个类继承Thread类后,可以在该类中覆盖run()方法,将实现该线程功能的代码写入run()方法中,然后调用Thread类中的start()方法执行线程。
run()方法的格式如下:
public void run(){
//...
}
如果start()方法调用一个已经启动的线程,系统会抛出Illegal Thread State Exception异常。
当执行一个线程程序时,会自动产生一个线程,主方法在该线程上运行,程序员负责启动自己的线程,代码如下:
public static void main(String[] args){
new ThreadTest().start();
}
2.实现Runnable接口
由于Java不支持多继承,所以程序员要想实现继承其他类来实现线程使用,就可以通过Runnable接口来实现。代码如下:
public class Thread extends Object implements Runnable
线程的生命周期
线程具有生命周期,包含七种状态:
- 出生状态:用户在调用线程实例start()方法之前,线程处于出生状态。
- 就绪状态;用户调用start()方法之后,线程处于就绪状态。
- 运行状态;线程得到系统资源后进入运行状态。
- 等待状态;运行状态下的线程调用wait()方法后,会进入等待状态。等待状态中的线程需要通过notify()方法才能被唤醒,notifyAll()方法是将所有处于等待状态下的线程唤醒。
- 休眠状态;线程调用Thread类中的sleep()方法时,会进入休眠状态。
- 阻塞状态;如果一个线程在运行状态下,发出输入/输出请求,线程会进入阻塞状态。在等待输入/输出结束时,线程进入就绪状态。
- 死亡状态:线程的run()方法执行完毕时,线程进入死亡状态。
线程的优先级
Java中,线程有其优先级,范围是1~10,默认值为5.可以使用Thread类的setPriority()方法来设定线程的优先级。必须在1~10之间。
一般都会将线程放入无限循环内,然后设置跳出循环的条件。
线程的控制
线程的控制包括线程的启动、挂起、状态检查,以及如何正确结束线程,由于在程序中使用多线程,因此需要合理的安排线程的执行顺序,对线程进行相应的控制。
1.线程的启动
一个新的线程在创建后处于初始状态,实际上并没有立刻进入运行状态,而是处于就绪状态,当轮到这个线程执行时,即进入可执行状态,开始执行线程run()方法中的代码。
执行run()方法是通过调用Thread类中的start()方法来实现的。调用start()方法启动线程的run()方法不同于一般的调用方法,调用一般方法时,必须等到一般方法执行完毕才能返回,对于start()方法来说,调用线程的start()方法后,start()方法告诉系统该线程准备就绪并可以启动run()方法后就返回,并继续执行调用start()方法下面的语句,这是,run()方法可能还在运行,这样,线程的启动和运行并行进行,实现了多任务操作。
2.线程的挂起
线程的挂起操作实质上就是使线程进入非可执行状态。有以下几种情况使线程进入非可执行状态:
- 调用sleep()方法使线程进入休眠状态,线程在指定时间内不会运行;
- 调用join()方法使现场挂起,如果某个线程在另一个线程t上调用t.join(),这个线程将被挂起,直到线程t执行完毕。
- 调用wait()方法使线程挂起,直到线程得到了notify()、notifyAll()消息,线程才会进入可执行状态。
- 线程在等待某个输入/输出完成。
sleep()方法是一个使线程暂停一段执行时间的方法,该时间由给定的毫秒数决定。
当一个线程A,现在需要插入线程B,并要求线程B先执行完毕,而后再执行现场A,此时可以使用THread类中的join()方法完成。当某个线程使用join()方法加入到另一个线程时,另一个线程会等待该线程执行完毕再继续执行。
还可以使用wait()方法与notify()方法结合,第一种方式可以使用wait()按照系统给定时间挂起;第二种方式是wait()与notify()方法配合使用,让wait()方法无限等下去,直到线程接收到notify()或notifyAll()为止。
需要注意,wait(),notify()与notifyAll()方法都被声明为final类,无法重新定义。
3.线程的结束
线程的结束从run()方法的结尾处返回,自然消亡且不能再被运行。