1.线程概念
java所谓多线程,顾名思义,就是多道线程执行线索,那么为什么要多线程呢?如果你的部分代码在执行某个i/o操作而受阻,那么程序的其他部分也不能执行,这样就严重的浪费了cpu,多线程机制就是为解决这个问题。
多进程并行执行时,在cpu上执行的某个进程因为等待某种资源而受阻时,多任务操作系统可以使进程挂起,而根据FIFO原则,时间片轮转等启动另一个不同的进程执行,直到前一进程获得
所需资源,才能唤醒该资源,让他继续执行。
这样,在多任务操作系统的调度下,可以让多个进程并行执行,能够较好地利用CPU资源,但仍然难以满足现代应用程序的需要。
例如,需要在同一应用程序中完成声音播放、图像显示、网络文件下载等多项工作,如果使用传统的单线程程序,就只能顺序的逐一实现,而使用多线程方法则可以并发实现。
进程把内存空间作为自己的资源之一,每个进程均有自己的内存单元,线程却共享内存空间,通过共享的内存 空间来交换信息,从而有利于提高效率。
java引入了优先级的概念,优先级越高的线程,获得cpu的权利越大,执行机会越多,java把优先级划分为10个等级,数值也爽啊,优先级越高,在thread类中定义了三个优先级常量:MIN_PRIORITY,MAX_PRIORITY和NORM_PRIORITY,其直分别是1,10,5.如果没有分配,java默认为norm_priority为5.
调度就是分配cpu资源,确定线程的执行顺序,java采用抢占式调度,优先级高的线程具有剥夺低优先级线程的执行权利。如果一个低优先级的线程正在执行,这时出现一个高优先级的线程,那么低优先级的线程就会停止执行,放弃cpu,退回等待队列中,等待下一轮的执行,而让高优先级的线程立即执行。如果具有相同优先级的线程,按照先来先服务的调度原则。
我们设计程序时,应该让高优先级的线程执行一段时间后能够交出使用权,可以使用sleep()方法暂时进入睡眠,从而让出cpu,使有相同优先级的线程和低优先级的线程有执行的机会。二是调用yield()而放弃cpu,这时和他有相同优先级的线程就有执行机会。
2.线程的生命周期
每个java程序都有一个缺省的主线程:对于application,主线程是main方法执行的线索,对于applet,主线程指挥浏览器加载并执行java小程序。要想实现多线程,必须在主线程中创建新的线程对象,java语言使用Thread及其子类的对象表达线程。,
1新建:当一个Thread类或子类对象被创建后进入这个状态,这时线程对象已被分配内存空间,其私有数据已被初始化,但该线程还未被调度,可用start(调度),或stop(终止);新 生线程一旦被调度,就将切换到可执行状态
2可运行:处于可执行环境随时可以被调度而执行,分两个子状态:运行状态和就绪状态;
3 阻塞: 由某种原因引起线程暂停执行。
4 死亡:线程执行完毕或另一线程调用stop()方法使其停止时,进入停止状态。他表示线程退出可运行状态,并且不可能再进入可运行状态。
Thread定义很多控制线程的方法:start()调用run()方法使线程开始执行; stop()立即停止,使其内部状态清零; suspend()暂停线程执行,线程的所有状态和资源保持不变,以后可以通过另一个线程调用resume()方法重新启动这个线程。 isAlive() 线程处于新建状态时,调用方法返回FALSE,当一个线程调用start()方法时,占用资源后,该线程run方法开始执行,在run方法结束前,即没有进入死亡状态之前,调用isAlive()返回true;,当线程进入死亡状态后,实体内存被释放,线程仍可以调用isalive();返回false;
创建线程方法:
生成Thread子类;生成一个类,声明实现runnable接口;无论使用哪一个,我们可以控制的关键性操作有两个:1定义用户线程的操作,即定义用户线程的run方法;2在适当的时候建立用户线程实例。
class NewThread extends Thread
{
…
public void run()
{
…
}
}
在需要创建NewThread这个线程的类或方法中,生成NewThread对象。
即
NewThread thread = new NewThread();
thread.start();class NewThreadRun implements Runnable
{
…
public void run()
{
…
}
}
用下面的代码创建并执行新线程
NewThreadRun n = new NewThreadRun();
Thread thread = new Thread(n);
thread.start();
Runnable是java.long包中的一个接口。任何一个类都可以实现这个接口,从而实现创建和执行线程的功能。实现Runnable接口的类必须覆盖接口中定义的run()方法,它仍然是完成具体任务的地方。
以上两种方法都可以创建和执行线程,前一种方法要求一定是Thread类的子类,后一种方法可以不是Thread类的子类,但必须实现Runnable接口,这种方法使用更加灵活。
有时还只能使用后一种方法,如某类已经定义为Applet类的子类,由于Java不允许多重继承,这时不能再定义它为Thread类的子类,此时只有声明其实现Runnable接口来创建和执行新线程。