线程控制
当同一时刻有多个线程处于可运行状态,它们需要排队等待CPU资源,每个线程会自动获得一个线程的优先级(Priority),优先级的高低反映线程的重要或紧急程度。可运行状态的线程按优先级排队,线程调度依赖建立在优先级基础上的“先到先服务”原则。
线程调度器按线程调度算法进行调度。
线程调度是抢占式调度:一个线程用完CPU之后,操作系统会根据线程优先级、线程饥饿情况等数据算出一个总的优先级并分配下一个时间片给某个线程执行。
暂停线程:join
Thread类提供了一个让线程等待另一个线程完成的方法----join()
方法。当在某个程序执行流中调用其他线程的join()方法时,调用线程将被阻塞,直到被join()方法加入的join()线程执行完为止。
join()方法通常由使用线程的程序调用,将大问题划分成许多小问题,每个小问题分配一个线程。当所有的小问题都得到处理后,再调用主线程来进一步操作。
join()方法有如下三种重载方式:
- join():等待被join的线程执行完成
- join(long milis):等待被join的线程时间最长为millis毫秒。如果在millis毫秒内被join的线程没有执行结束,则不再等待
- join(long millis,int nanos):等待被join的线程的时间最长为millis毫秒加nanos毫微秒。通常很少使用,原因有两个:程序对时间的精度无法精确到毫微秒;计算机硬件、操作系统本身也无法精确到毫微秒。
守护线程
有一种线程,它是在后台执行的,它的任务是为其他的线程提供任务,这种线程被称为“后台线程(Daemon Thread)”,又被称为“守护线程”或“精灵线程”。JVM的垃圾回收线程就是经典的后台线程。
- 后台线程有一个特点:如果所有的前台线程都死亡,后台线程就会自动死亡。
- 调用Thread对象的setDaemon(true)方法可将指定线程设置为后台线程
注意:
- setDaemon(true)必须在start()方法之前调用,否则会引发IllegalThreadStateException异常。
线程睡眠:sleep
如果需要让当前正在执行的线程暂停执行一段时间并进入阻塞状态,则可以通过调用Thread类的静态方法sleep()方法实现。sleep()放法有两种重载形式:
- static void sleep(long millis):让当前正在执行的线程暂停执行millis毫秒,并进入阻塞状态。受到系统计时器和线程调度器的精度与准确度的影响。
- static void sleep(long millis,int nanos):毫秒+毫微秒(很少使用)
当前线程调用sleep()方法进入阻塞状态后,在其睡眠时间段内,该线程不会获得执行的机会,即使系统中没有其他可执行的线程,处于sleep()中的线程也不会执行,因此sleep()方法常用来暂停程序的执行。
线程让步:yield
yield()方法是一个和sleep()方法有点类似的方法,它也是Thread类提供的一个静态方法,它可以让当前执行的线程暂停,但它不会阻塞该线程,它只是将该线程转入就绪状态。yield()方法只是让当前线程暂停执行一下,让系统的线程调度器重新调度一次,完全可能的情况是:当某个线程调用了yield()方法暂停之后,线程调度器又将其调度出来重新执行。
实际上,当某个线程调用了yield()方法暂停之后,只有优先级与当前线程相同、或优先级比当前线程高的处于就绪状态的线程才会获得执行的机会。
sleep()和yield()的区别
- sleep()方法暂停当前线程后,会给其他线程执行机会,不会理会其他线程的优先级;但yield()方法只会给优先级相同、或优先级更高的线程执行机会。
- sleep()方法会将线程转入阻塞状态,直到经过阻塞时间才会转入就绪状态;而yield()不会将线程转入阻塞状态,它只是强制当前线程进入就绪状态。因此完全有可能某个线程调用yield()方法暂停之后,立即获得处理器资源被执行。
- sleep()方法声明抛出了InterruptedException异常,所有调用sleep()方法时要么捕捉该异常,要么显示声明抛出该异常;而yield()方法则没有声明抛出任何异常。
- sleep()方法比yield()方法有更好的可移植性。
改变线程优先级
每个线程在执行时都有一定的优先级,优先级高的线程获得较多的执行机会,而优先级低的线程则获得较少的执行机会。
每个线程默认的优先级都与创建它的父线程的优先级相同,在默认情况下,main线程具有普通优先级,由main线程创建的子线程也具有普通优先级。
Thread类提供了setPriority(int newPriority)
、getPriority()
方法来设置和返回指定线程的优先级,其中setPriority(int newPriority)方法的参数是一个整数,范围是1~10,也可以使用Thread类的如下三个静态变量:
- MAX_PRIORITY:10
- MIN_PRIORITY:1
- NORM_PRIORITY:5