1、 线程(thread)是指程序的运行流程。“多线程”的机制可以同时运行多个程序块,使程序运行的效率更高,也解决了传统程序设计语言所无法解决的问题。
1) 程序与进程:
程序并不能单独运行,只有将程序装载到内存中,系统为它分配资源才能运行,而这种执行的程序就称之为进程。程序和进程的区别就在于:程序是指令的集合,它是进程运行的静态描述文本;进程是程序的一次执行活动,属于动态概念。进程的优点,它提供了多道编程,让我们感觉我们每个人都拥有自己的CPU和其他资源,可以提高计算机的利用率。缺点:进程只能在一个时间干一件事,如果想同时干两件事或多件事,进程就无能为力了。进程在执行的过程中如果阻塞,例如等待输入,整个进程就会挂起,即使进程中有些工作不依赖于输入的数据,也将无法执行。
2)进程和线程
-
进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。
-
线程是进程的一个实体, 是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。
-
一个线程可以创建和撤销另一个线程,同一个进程中的多个线程之间可以并发执行。
3)进程和线程的差别
进程和线程的主要差别在于它们是不同的操作系统资源管理方式。进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序 健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。
2、 类里要激活线程的两项准备:
(1)、此类必须是扩展自 Thread 类,使自己成为它的子类。
(2)、线程的处理必须编写在 run()方法内。
3、 run()方法是定义在 Thread 类里的一个方法,因此把线程的程序代码编写在 run()方法内,所做的就是覆盖的操作。多线程的定义语法:
class 类名称 extends Thread // 从 Thread 类扩展出子类
{
属性
方法...
修饰符 run(){ // 复写 Thread 类里的 run()方法
以线程处理的程序;
}
}
4、 Runnable 接口里声明了抽象的 run()方法,因此必须在实现 Runnable 接口的类里明确定义 run()方法。
JAVA 程序只允许单一继承,即一个子类只能有一个父类,所以在 Java 中如果一个类继承了某一个类,同时又想采用多线程技术的时,就不能用 Thread 类产生线程,因为 Java 不允许多继承,这时就要用 Runnable接口来创建线程了。
多线程的定义语法:
class 类名称 implements Runnable // 实现 Runnable 接口
{
属性
方法...
修饰符 run(){
// 复写 Thread 类里的 run()方法
以线程处理的程序;
}
}
实现Runnable接口方式相对直接继承thread方法的优势:
(1) 适合多个相同程序代码的线程去处理同一资源的情况,把虚拟 CPU(线程)同程序的代码、数据有效分离,较好地体现了面向对象的设计思想。
(2) 可以避免由于 Java 的单继承特性带来的局限。开发中经常碰到这样一种情况,即:当要将已经继承了某一个类的子类放入多线程中,由于一个类不能同时有两个父类,所以不能用继承 Thread 类的方式,那么就只能采用实现 Runnable 接口的方式了。
(3) 增强了程序的健壮性,代码能够被多个线程共享,代码与数据是独立的。当多个线程的执行代码来自同一个类的实例时,即称它们共享相同的代码。多个线程可以操作相同的数据,与它们的代码无关。当共享访问相同的对象时,即共享相同的数据。当线程被构造时,需要的代码和数据通过一个对象作为构造函数实参传递进去,这个对象就是一个实现了Runnable 接口的类的实例。
几乎所有多线程应用都可用实现 Runnable 接口方式。
5、 每一个线程,在其创建和消亡之前,均会处于下列五种状态之一:创建、就绪、运行、阻塞、终止。
创建:Thread thread=new Thread();
就绪:start();start()方法可以启动线程,线程将进入线程队列排队,等待 CPU 服务,这表明它已经具备了运行条件。
运行:run()方法,run()方法定义了该线程的操作和功能,当就绪状态的线程被调用并获得处理器资源时,线程就进入了运行状态。
阻塞:在可执行状态下,如果调用 sleep()、suspend()、wait()等方法,线程都将进入堵塞状态。堵塞时,线程不能进入排队队列,只有当引起堵塞的原因被消除后,线程才可以转入就绪状态。
终止:线程调用 stop()方法时或 run()方法执行结束后,线程即处于死亡状态。处于死亡状态的线程不具有继续运行的能力。
(1)该线程调用对象的 wait()时。
(2)该线程本身调用 sleep()时。
(3)该线程和另一个线程 join()在一起时。
7、 被冻结因素消失的原因有:
(1)如果线程是由调用对象的 wait()方法所冻结,则该对象的 notify()方法被调用时可解除冻结。
(2)线程进入休眠(sleep)状态,但指定的休眠时间到了。
8、 当线程的 run()方法运行结束,或是由线程调用它的 stop()方法时,则线程进入消亡状态。
在程序中也可以通过 isAlive()方法来测试线程是否已经启动而且仍然在启动。
10、要强制某一线程运行,可用 join()方法。
11、join()方法会抛出 InterruptedException 的异常,所以编写时必须把 join()方法编写在 try-catch 块内。
12、当多个线程对象操纵同一共享资源时,要使用 synchronized 关键字来进行资源的同步处理。