每个线程都与优先级设置相关.线程的优先级部分决定了相对于其他活动线程,某个线程可以被分配多少CPU时间.总体而言,优先级低的分配的时间少,优先级高的分配的时间多.正如你所想象的,CPU时间分配的多少对线程的执行特点和他与系统中同时执行的其他线程之间的交互作用有着深远的影响.
还有一点很重要,即除了线程的优先级以外,还有一些其他因素也对分配给线程多少CPU时间有影响.例如,如果一个高优先级的线程正在等待某一资源(可能是键盘输入),那么他就会被阻塞,而运行一个较低优先级的线程.然而当高优先级的线程获得了对资源的访问权以后,他就可以占用低优先级线程的CPU时间,继续执行.另一个相应线程调度的因素就是操作系统实现多任务的方法.因此,仅仅将高优先级赋予一个线程,将低优先级赋予另一个线程并不一定意味着前一个线程就会比后一个线程运行的快或者获得的运行时间更多.高优先级的线程仅仅具有占用更多CPU时间的可能.
当启动子线程时,其优先级设置与父线程相等.可以通过调用Thread的成员方法setPriority()来修改线程的优先级.其基本形式如下所示:
final void setPriority(int level)
这里,level为调用线程指定了新的优先级设置.level的值必须在MIN_PRIORITY和MAX_PRIORITY的范围内.目前,这些值分别为1和10.要想把线程返回为默认优先级,需要指定当前为5的NORM_PRIORITY.这些优先级都在Thread中定义为 static final变量.
通过调用Thread的getPriority()方法,可以获得当前优先级设置,如下所示:
final int getPriority()
下面的示例说明了不同优先级的两个线程.这些线程作为priority的实例被创建.run()方法包含一个统计迭代次数的循环.当任何一个统计值达到1000000或静态变量stop为true时,循环停止.最初,设置stop为false,第一个完成统计数的线程将把stop设置为true.这会导致第二个线程在他的下一个时间片终止.每次通过循环时,currentName中的字符串都会与正在执行线程的名字进行比较.如果他们不相等,就意味着发生了任务转换.每次发生任务转换时,将显示新的线程名字,并且给currentName赋予新线程的名字.这样就可以非常精确的观察每个线程访问CPU的频度.在两个线程都停止后,将显示每个循环的迭代次数.
public class test2 { // @param args public static void main(String args[]) { MyThread mt1 = new MyThread("child#HIGH"); MyThread mt2 = new MyThread("child#LOW"); mt1.setPriority(Thread.NORM_PRIORITY+2); mt2.setPriority(Thread.NORM_PRIORITY-2); mt1.start(); mt2.start(); try { mt1.join(); mt2.join(); }catch(InterruptedException exc) { System.out.println("main thread interrupted"); } System.out.println("High Priority count = "+mt1.count); System.out.println("Low Priority count = "+mt2.count); } } class MyThread extends Thread implements Runnable { String thrdName; int count; static boolean stop = false; static String currentName; MyThread(String name) { thrdName = name; } public void run() { System.out.println(thrdName+" start"); do { count++; }while(count<1000000 && stop == false); stop = true; } }
输出结果:
child#HIGH start child#LOW start High Priority count = 1000000 Low Priority count = 167298
问:操作系统的任务实现方式会影响分配给线程的CPU时间吗?
答:除了线程的优先级设置以外,影响线程执行的最重要的因素就是操作系统实现多任务和调度的方法.一些操作系统至少偶尔会使用抢占式的多任务方法,为每个线程分配一个时间片.还有一些系统使用非抢占式的调度方法,一个线程必须放弃执行后,另一个线程才能执行.在非抢占式系统中,一个线程很容易占用CPU,无法使其他线程运行.