APP下载

浅谈Java多线程编程

2011-08-15

科技传播 2011年3期
关键词:监视器程式线程

崔 妍

哈尔滨铁道职业技术学院,黑龙江 哈尔滨 150081

1 多线程编程形式

创建线程需要一定的步骤,首先要创建线程,然后为其指定工作,当工作结整后再毙掉该线程。通常在Java中线程的编程形式通常有两种,第一种所创建的线程类是经过继承Thread类实现的,再用该线程重载run();另外一种是建立一个Runnable接口类,因为Java无法支持多继承性,因此如果要求类通过线程方式运行,并且继承其它类,就要采用唯一的方法——run()来实现Runnable接口,该方法就成为线程主函数。不同的程序运行方式不同所产生的结果也必然不同,主要由于两个原因,一是由于循环中有个随机暂停,另外一个重要的原因是由于无法保证线程的执行时间。Java按照其时间表来运行这些进程,每个线程可以有一个优先级与其相关联。

2 设置线程的优先级

利用调度程序来完成线程的运行,调度方法有协作和抢先两形式,相比之下抢先式在资源调度方面较之协作式有更大优势,Java恰恰支持抢先式,所以分配优先级能力在多线程程式中十分重要,线程调度的决策就是以其为参照进行,程式中的某些部分也会根据其重要程度而变化,从而保证它的优先级与其价值是相对应的。优先级的设这要注意几点:一是确定优先级必须采用1~10之间的整数;二是父线程的优先级要被子线程所继承;三是线程的优先级可以通过setpriority()的调用进行改变。Java会先择最高优先级的线程来执行,因此编写程式时,要注意有些线程优先级较低,但也要给其执行的机会,此时优先级高的线程可以适当进入休眠状态。

3 同步机制

在多线程程式中,所有线程都是各自独立的执行体,不过线程代码的模式却是相同的,如果这些线程要协同工作,那么一定要注意其线程代码是不是能够重入控制,所以Java就提供了相应的同步机制,从而阻止多个线程的一个或者多个关键代码在任意时间执行该代码。该机制是建立在锁的概念和监视器基础上的,其中监视器是关键代码周围的保护,锁则是监视器阻止线程进入监视器的软件。其基本理念是:如果一个线程要进入监视器所监视的关键代码,该线程要获取一个与之相关的锁;如果别的线程在使用这个锁,那么Java就会强制性的要求其在一个与锁以及监视器相关的区域进行等待;当锁被释放时,Java就移出等待状态中的线程,同意其获取琐,并对监视器的关键代码进行相应处理。Java自带monitorexit以及monitorenter指令与锁和监视器同步工作,不过这种级别相对较低,我们可以使用以下两种方法执行线程同步:

3.1 synchronized方法

把synchronized的关键字加入到方法声明中,来声明synchronized()方法。在synchronized()方法中,类成员变量访问由synchronized()方法控制,每个类实例都会对应一个琐,如果synchronized()方法要执行就要获取相应的锁,否则会阻塞所属的线程。一旦该方法进入执行状态就会独占一个锁,并且直至其返回才会释放。这种机制可以确保在同一时间对每个类实例,它的声明为synchronized的成员函数最多只能有一个处于执行状态,从而避免了类成员变量访问产生冲突。JAVA中每个类都对应一把这样的锁,因此要控制其访问类的静态成员变量,就可以把类的静态成员函数声明为synchronized。

3.2 synchronized块

上述方法中,如果代码量较多,则声明的效率会大受影响,因此我们可以用synchronized块来解决该问题。synchronized块中要获取SynObject对应的锁才可以执行,因为可以对任何代码块并且上锁的对象可以任意指定,因此相对synchronized块方法有较高的灵活性。

4 线程阻塞和死锁

既然进行多线程编程就不得不考虑访问共享资源的问题。虽然上述JAVA同步机制可以控制线程代码重入,但很多时候多个线程在各自的执行过程中,会访问诸如存储处理等同一处资源,因为线程不同,其所执行的时机也不一致,所以为了防止不同线程在访问共享资源时修改其内容,JAVA就提供了相应的阻塞机制来解决该问题,支持阻塞的方法有以下几种:

1)线程阻塞的方法

第一种是sleep():该方法同意指定毫秒为单位的时间段作为参数,可以使线程在其指定时间段内不用得到CPU时间还可以进入阻塞状态,当指定时间过去后,线程即可进入执行状态;第二种是resume()以及suspend():要将这两种方法进行配合使用,suspend()会使线程保持阻塞状态,并且无法自动恢复,只有当调用resume()时,才可以重新使线程进入执行状态;第三种是yield():该方法使得线程放弃当前得到的CPU时间,但是无法阻塞线程,因此线程仍然处于执行状态中,并且可以随时再取得CPU时间。当调用yield()时其效果等价于调度程序,认为该线程已经执行了足够的时间,转达向另一个线程;第四种方法是notify()以及wait():要将两种方法配合使用。其中wait()有两种形式使线程进入阻塞状态,一种是同意指定一段时间为参数,如果与其以对应的notify()超出所指定的时间或者被调用,线程可以重新执行;另外一种是不指定参数,此时就要等到调用notify()才可以解除。这种配套使用的方法与上述resume()、suspend()的区别就在于该方法阻塞时不会释放锁,而resume()、suspend()刚好相反。

2)注意事项

notify()和wait()属于Thread类,而resume()和suspend()则属于Object类,即所有对象都有这一对方法,在阻塞时要释放所占用的锁。由于任何对象都有锁,所以调用任何对象wait()法都会导致线程阻塞,且对象的锁也被释放;如果调用任何对象notify()法,就会导致调用该对象的wait()法阻塞线程中随机选择任意一个解除阻塞。此外,调用不指定超时期限的wait()法以及suspend()法,都有产生死锁的可能,JAVA在语言级别上并不支持避免死锁,因此在编程过程中要注意加以控制,避免死锁。

[1]王昕.Java多线程机制在并发编程中的应用[J].现代商贸工业,2010(17).

[2]张迎,徐洪珍,汤彬.耘夕扣多线程技术及其在网络编程中的应用[J].科技广场,2008(5).

[3]李丹塞.Java多线程编程技术试议[J].软件开发与设计,2010(2).

[4]赖万钦.JAVA多线程编程技术探讨[J].福建电脑,2008(6).

[5]袁云,邵时.基于多核处理器并行系统的任务调度算法[J].计算机应用,2008(28).

猜你喜欢

监视器程式线程
增程式电动汽车续驶里程的延长优化
英语程式语可学性的语言模因论解读
基于Motor-CAD的增程式电动车发电机设计
基于FPGA消息识别和过滤的1553B总线监视器的设计
浅谈linux多线程协作
仿生监视器
深耕广电,时代奥视监视器“花香遍墙内外”
高速公路智能网络监视器的应用
增程式电动环卫车APU启停控制策略的设计
基于上下文定界的Fork/Join并行性的并发程序可达性分析*