1.什么是线程java
通常来讲,咱们把正在计算机中执行的程序叫作"进程"(Process) ,而不将其称为程序(Program)。所程序员
谓"线程"(Thread),是"进程"中某个单一顺序的控制流。新兴的操做系统,如Mac,Windows NT,Windows 95算法
等,大多采用多线程的概念,把线程视为基本执行单位。线程也是Java中的至关重要的组成部分之一。 浏览器
甚至最简单的Applet也是由多个线程来完成的。在Java中,任何一个Applet的paint()和update()方网络
法都是由AWT(Abstract Window Toolkit)绘图与事件处理线程调用的,而Applet 主要的里程碑方法——多线程
init(),start(),stop()和destory() ——是由执行该Applet的应用调用的。 并发
单线程的概念没有什么新的地方,真正有趣的是在一个程序中同时使用多个线程来完成不一样的任务。操作系统
某些地方用轻量进程(Lightweig ht Process)来代替线程与真正进程的类似性在于它们都是单一顺序控线程
制流。然而线程被认为轻量是因为它运行于整个程序的上下文内,能使用整个程序共有的资源和程序环境设计
。
做为单一顺序控制流,在运行的程序内线程必须拥有一些资源做为必要的开销。例如,必须有执行堆
栈和程序计数器。在线程内执行的代码只在它的上下文中起做用,所以某些地方用"执行上下文"来代替"
线程"。
2.线程属性
为了正确有效地使用线程,必须理解线程的各个方面并了解Java 实时系统。必须知道如何提供线程
体、线程的生命周期、实时系统如 何调度线程、线程组、什么是幽灵线程(Demo nThread)。
(1)线程体
全部的操做都发生在线程体中,在Java中线程体是从Thread类继承的run()方法,或实现Runnable接口
的类中的run()方法。当线程产生并初始化后,实时系统调用它的run()方法。run()方法内的代码实现所
产生线程的行为,它是线程的主要部分。
(2)线程状态
附图表示了线程在它的生命周期内的任什么时候刻所能处的状态以及引发状态改变的方法。这图并非
完整的有限状态图,但基本归纳了线程中比较感兴趣和广泛的方面。如下讨论有关线程生命周期以此为据
。
●新线程态(New Thread)
产生一个Thread对象就生成一个新线程。当线程处于"新线程"状态时,仅仅是一个空线程对象,它还
没有分配到系统资源。所以只能启动或终止它。任何其余操做都会引起异常。
●可运行态(Runnable)
start()方法产生运行线程所必须的资源,调度线程执行,而且调用线程的run()方法。在这时线程处
于可运行态。该状态不称为运行态是由于这时的线程并不老是一直占用处理机。特别是对于只有一个处
理机的PC而言,任什么时候刻只能有一个处于可运行态的线程占用处理 机。Java经过调度来实现多线程对处
理机的共享。
●非运行态(Not Runnable) :
当如下事件发生时,线程进入非运行态。
①suspend()方法被调用;
②sleep()方法被调用;
③线程使用wait()来等待条件变量;
④线程处于I/O等待。
●死亡态(Dead)
当run()方法返回,或别的线程调用stop()方法,线程进入死亡态 。一般Applet使用它的stop()方法
来终止它产生的全部线程。
(3)线程优先级
虽然咱们说线程是并发运行的。然而事实经常并不是如此。正如前面谈到的,当系统中只有一个CPU时,
以某种顺序在单CPU状况下执行多线程被称为调度(scheduling)。Java采用的是一种简单、固定的调度法
,即固定优先级调度。这种算法是根据处于可运行态线程的相对优先级来实行调度。当线程产生时,它继
承原线程的优先级。在须要时可对优先级进行修改。在任什么时候刻,若是有多条线程等待运行,系统选择优
先级最高的可运行线程运行。只有当它中止、自动放弃、或因为某种缘由成为非运行态低优先级的线程
才能运行。若是两个线程具备相同的优先级,它们将被交替地运行。
Java实时系统的线程调度算法仍是强制性的,在任什么时候刻,若是一个比其余线程优先级都高的线程的
状态变为可运行态,实时系统将选择该线程来运行。
(4)幽灵线程
任何一个Java线程都能成为幽灵线程。它是做为运行于同一个进程内的对象和线程的服务提供者。
例如,HotJava浏览器有一个称为" 后台图片阅读器"的幽灵线程,它为须要图片的对象和线程从文件系统
或网络读入图片。
幽灵线程是应用中典型的独立线程。它为同一应用中的其余对象和线程提供服务。幽灵线程的run()
方法通常都是无限循环,等待服务请求。
(5)线程组 :
每一个Java线程都是某个线程组的成员。线程组提供一种机制,使得多个线程集于一个对象内,能对它
们实行总体操做。譬如,你能用一个方法调用来启动或挂起组内的全部线程。Java线程组由ThreadGroup
类实现。
当线程产生时,能够指定线程组或由实时系统将其放入某个缺省的线程组内。线程只能属于一个线程
组,而且当线程产生后不能改变它所属的线程组。
3.多线程程序
对于多线程的好处这就很少说了。可是,它一样也带来了某些新的麻烦。只要在设计程序时特别当心
留意,克服这些麻烦并不算太困难。
(1)同步线程
许多线程在执行中必须考虑与其余线程之间共享数据或协调执行状态。这就须要同步机制。在Java
中每一个对象都有一把锁与之对应。但Java不提供单独的lock和unlock操做。它由高层的结构隐式实现,
来保证操做的对应。(然而,咱们注意到Java虚拟机提供单独的monito renter和monitorexit指令来实现
lock和unlock操做。)
synchronized语句计算一个对象引用,试图对该对象完成锁操做, 而且在完成锁操做前中止处理。当
锁操做完成synchronized语句体获得执行。当语句体执行完毕(不管正常或异常),解锁操做自动完成。做
为面向对象的语言,synchronized常常与方法连用。一种比较好的办法是,若是某个变量由一个线程赋值
并由别的线程引用或赋值,那么全部对该变量的访问都必须在某个synchromized语句或synchronized方法
内。
如今假设一种状况:线程1与线程2都要访问某个数据区,而且要求线程1的访问先于线程2, 则这时仅
用synchronized是不能解决问题的。这在Unix或WindowsNT中可用Simaphore来实现。而Java并不提供。
在Java中提供的是wait()和notify()机制。使用以下:
synchronized method - 1(...) {
call by thread 1.
//access data area;
available = true;
notify()
}
synchronized method - 2(...) { //call by thread 2.
while (!available)
try {
wait(); //wait for notify().
} catch (Interrupted Exception e) {
}
}
//access data area
}
其中available是类成员变量,置初值为false。
若是在method-2中检查available为假,则调用wait()。wait()的做用是使线程2进入非运行态,而且
解锁。在这种状况下,method-1能够被线程1调用。当执行notify()后。线程2由非运行态转变为可运行态
。当method-1调用返回后。线程2
可从新对该对象加锁,加锁成功后执行wait()返回后的指令。这种机制也能适用于其余更复杂的状况。 ;
(2)死锁
若是程序中有几个竞争资源的并发线程,那么保证均衡是很重要的。系统均衡是指每一个线程在执行过
程中都能充分访问有限的资源。系统中没有饿死和死锁的线程。Java并不提供对死锁的检测机制。对大
多数的Java程序员来讲防止死锁是一种较好的选择。最简单的防止死锁的方法是对竞争的资源引入序号,
若是一个线程须要几个资源,那么它必须先获得小序号的资源,再申请大序号的资源。
4.小结
线程是Java中的重要内容,多线程是Java的一个特色。虽然Java的同步互斥不如某些系统那么丰富,
但适当地使用它们也能收到满意的效果。
run方法返回后线程进入死亡态
死亡态(Dead)
当run()方法返回,或别的线程调用stop()方法,线程进入死亡态 。一般Applet使用它的stop()方法
来终止它产生的全部线程。
更多视频教程,尽在麦子学院(http://www.maiziedu.com/)