一.进程与线程
进程是程序动态执行的一次过程,它经历了代码加载,执行到执行完毕的一个完整过程,这个过程也是进程本身产生,发展到消亡的过程。多进程操作系统能同时运行多个进程,由于CPU具有分时机制,所以每个进程都能循环获得自己的CPU时间片。由于CPU执行速度非常快,使得所有进程好像是同时运行一样。
线程是比进程更小的执行单位,线程是在进程的基础之上的进一步划分。多线程是指一个进程在执行过程中可以产生多个线程,这些线程可以同时存在,同时运行,一个进程可以包含多个同时执行的线程。区别如下图:
二.Java中线程的实现
1.继承Thread类
Thread类是在java.lang包中定义的,只要继承了Thread类,此类就称为多线程类。在此类中必须要明确的覆写Thread类中run()方法,此方法称为线程的主体,定义格式如下:
调用Thread类中的start()方法可以启动线程。线程的运行需要本地操作系统的支持,start()方法的部分定义如下图:
可知声明使用了native关键字,这个关键字表示调用本机的操作系统底层函数。如果一个类通过继承Thread类实现,那么只能调用一次start()方法,如果重复调用会报"IllegalThreadStateException"异常。代码实例如下:
class MyThread extends Thread{
private String name;
public MyThread(String name){
this.name = name;
}
public void run(){
for(int i = 0;i < 10;i++){
System.out.println(name+"运行i,="+i);
}
}
}
public class ThreadDemo {
public static void main(String[] args) {
MyThread m1 = new MyThread("线程A");
MyThread m2 = new MyThread("线程B");
m1.start();
m2.start();
}
}
线程B运行i,=0
线程A运行i,=0
线程B运行i,=1
线程A运行i,=1
线程B运行i,=2
线程A运行i,=2
线程B运行i,=3
线程A运行i,=3
线程B运行i,=4
线程A运行i,=4
线程B运行i,=5
线程A运行i,=5
线程B运行i,=6
线程A运行i,=6
线程B运行i,=7
线程A运行i,=7
线程B运行i,=8
线程A运行i,=8
线程A运行i,=9
线程B运行i,=9
结果不唯一
2.实现Runnable接口
Runnable接口中只定义了一个抽象方法:public void run();通过接口实现多线程的方法如下:
实际上实现接口还是要通过调用start()方法启动线程的。Thread类中有二个构造方法用来接收Runnable接口的子类实例对象,以此启动线程。
public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0);
}
public Thread(Runnable target, String name) {
init(null, target, name, 0);
}
无论哪种方式,都需要Thread类来启动线程。
class MyThread implements Runnable{
private String name;
public MyThread(String name){
this.name = name;
}
public void run(){
for(int i = 0;i < 10;i++){
System.out.println(name+"运行i,="+i);
}
}
}
public class ThreadDemo {
public static void main(String[] args) {
MyThread m1 = new MyThread("线程A");
MyThread m2 = new MyThread("线程B");
Thread r1 = new Thread(m1);
Thread r2 = new Thread(m2);
r1.start();
r2.start();
}
}
线程A运行i,=0
线程B运行i,=0
线程B运行i,=1
线程B运行i,=2
线程B运行i,=3
线程B运行i,=4
线程B运行i,=5
线程B运行i,=6
线程B运行i,=7
线程B运行i,=8
线程B运行i,=9
线程A运行i,=1
线程A运行i,=2
线程A运行i,=3
线程A运行i,=4
线程A运行i,=5
线程A运行i,=6
线程A运行i,=7
线程A运行i,=8
线程A运行i,=9
3.区别和联系
实现Runnable接口比继承Thread类有以下优势:
- 1.适合多个相同程序代码的线程去处理同一资源的情况
- 2.可以避免单继承带来的局限
- 3.增强了程序的健壮性,代码能够被多个程序共享,代码与数据是独立的。
三.线程的状态
任何线程都有创建,就绪,运行,阻塞,死亡五种状态。线程转换如下所示:
1.创建状态
在程序中用构造方法创建一个线程对象时,新的线程对象便处于新建状态,此时它已经有了自己的内存空间和其它资源,但它还是处于不可运行的状态。如:Thread thread = new Thread();
2.就绪状态
调用新建线程的start()方法就可以启动线程,启动时线程就进入了就绪状态,它将进入就绪队列排队,等待CPU服务。
3.运行状态
当就绪状态的线程被调用并获得处理器资源时,线程进入了运行状态,它会自动调用run()方法,方法中定义了该线程的操作和功能。
4.阻塞状态
一个正在执行的线程在一些特殊情况下,比如被人为挂起或较耗时的输入输出时,将让出CPU并中止自己的执行进入堵塞状态,此时它不能进入就绪状态,只有当阻塞状态的原因消除时才能重新进入就绪状态。在可执行状态下,调用sleep(),wait(),suspend()等方法可进入阻塞状态。
5.死亡状态
线程调用stop()方法或者run()方法执行完毕后,即处于死亡状态,此时线程不再具有运行的能力。
四.线程的操作方法
线程的操作方法主要在Thread类中,如下图所示:
图七为线程优先级,优先级越高越有可能先执行,但哪个线程先执行是由CPU调度决定的。