一、Java的优先级
Java提供了一个线程调度器来监控程序启动后进去就绪状态的所有线程。线程调度器通过线程的优先级来决定调度哪些线程执行。一般来说,Java的线程调度器采用时间片轮转算法使多个线程轮转获得CPU的时间片。然而根据实际情况,每个线程的重要程序也不相同,有时候我们想让一些线程优先执行,那么我们可以将他的优先级调高一下,这样它们获得的时间片会多一些。
多个线程处于就绪状态时,若这些线程的优先级相同,则线程调度器会按时间片轮转方式或独占方式来分配线程的执行时间。
Java中线程优先级用1~10来表示,分为三个级别:
低优先级:1~4,其中类变量Thread.MIN_PRORITY最低,数值为1;
默认优先级:如果一个线程没有指定优先级,默认优先级为5,由类变量Thread.NORM_PRORITY表示;
高优先级:6~10,类变量Thread.MAX_PRORITY最高,数值为10。
注意:具有相同优先级的多个线程,若它们都为高优先级Thread.MAX_PRORITY,则每个线程都是独占式的,也就是这些线程将被顺序执行;
若它们优先级不是高优先级,则这些线程将被同时执行,可以说是无序执行。
public class PriorityDemo extends Thread { public PriorityDemo(String name) { super(name); } @Override public void run() { for (int i=1;i<4;i++){ System.out.println(this.getName() + "循环了:" + i + "次"); } } } public class PriorityDriver { public static void main(String[] args) { System.out.println("当前线程位:" + Thread.currentThread().getName() + ",优先级为:" + Thread.currentThread().getPriority()); PriorityDemo thread1 = new PriorityDemo("thread1"); PriorityDemo thread2 = new PriorityDemo("thread2"); PriorityDemo thread3 = new PriorityDemo("thread3"); thread1.setPriority(MIN_PRIORITY); thread3.setPriority(MAX_PRIORITY); thread1.start(); thread2.start();
thread3.start(); } }
运行结果如下:由结果可以看出,不是高优先级的线程就一定先比低优先级执行完,而是高优先级线程先执行的概率比低优先级的线程高。
二、isAlive()方法
isAlive()方法用来判断线程目前是否正在执行,可以用来判断线程是否执行完毕。
如果线程已被启动并且未被终止,则返回true,但是没有进一步判断线程是可运行的或是阻塞的;
如果线程是新创建的或已被终止的,则返回false。
public class IsAliveDemo extends Thread { public IsAliveDemo(String name) { super(name); } @Override public void run() { for (int i=1;i<4;i++){ System.out.println(Thread.currentThread().getName() + "循环了" + i + "次"); } } } public class IsAliveDriver { public static void main(String[] args) { IsAliveDemo thread1 = new IsAliveDemo("thread1"); IsAliveDemo thread2 = new IsAliveDemo("thread2"); thread1.start(); System.out.println("当前线程对象为:" + Thread.currentThread().getName()); System.out.println("线程thread1是否处于活动状态?" + thread1.isAlive()); System.out.println("线程thread2是否处于活动状态?" + thread2.isAlive()); } }
结果如下:
三、yield()方法
yield()方法是Thread的类的类方法,它的作用是将当前正在执行的线程暂停并放置就绪线程队列最后,让Java线程调度器重新调度处于就绪状态的线程,若队列为空(处于就绪状态的线程仅有一个),则yield方法无效。
一般来说,重新调度之后与被暂停线程优先级相同的或比它优先级高的线程对象获取CPU使用权的可能性较大,但也有可能重新调度的仍是被暂停的同一个线程对象。
public class YieldDemo extends Thread { public YieldDemo(String name) { super(name); } @Override public void run() { for (int i=1;i<11;i++){ System.out.println(this.currentThread().getName() + "循环了" + i + "次"); if (i == 5){ //暂停当前正在执行的线程,让CPU重新调度 this.currentThread().yield(); } } } } public class YieldDriver { public static void main(String[] args) { //创建三个Yield线程对象 YieldDemo thread1 = new YieldDemo("thread1"); YieldDemo thread2 = new YieldDemo("thread2"); YieldDemo thread3 = new YieldDemo("thread3"); //设置它们的优先级 thread1.setPriority(Thread.MIN_PRIORITY); thread2.setPriority(Thread.NORM_PRIORITY); thread3.setPriority(Thread.MAX_PRIORITY); //启动三个线程对象 thread1.start(); thread2.start(); thread3.start(); } }
四、join()方法
join()方法的作用是等待调用join方法的线程执行完毕,再执行其他线程。
如果当前正在执行线程对象T1,再T1的执行流中调用了线程对象T2的join()方法,那么线程T1将处于阻塞状态直到线程T2执行完毕为止。
join()方法还有一种形式,“join(long t)”,该方法的参数t为等待时间,作用是等待当前加入的线程对象执行t毫秒,如果等待时间过去了,那么进入阻塞状态的线程就不再等待加入的线程对象。
public class JoinDemo extends Thread { public JoinDemo(String name) { super(name); } @Override public void run() { System.out.println("开始执行" + Thread.currentThread().getName() + "线程"); for (int i=1;i<6;i++){ System.out.println(this.getName() + "运行了" + i + "次"); } System.out.println(Thread.currentThread().getName() + "线程执行完毕!"); } } public class JoinDriver { public static void main(String[] args) { System.out.println("当前执行线程为:" + Thread.currentThread().getName()); //实例化线程1#并启动 new JoinDemo("1#").start(); for (int j=1;j<11;j++){ if (j == 5){ JoinDemo jd = new JoinDemo(j + "#"); jd.start(); try { jd.join(); } catch (InterruptedException e) { e.printStackTrace(); } } } //实例化线程2#并启动 new JoinDemo("2#").start(); } }
运行结果如下:由结果可知,在多核CPU下,线程1#和5#会抢夺CPU使用权,但是线程2#是无法与5#抢占CPU的时间片的。
join()方法可以用于当主线程(例子中的main)处理完其他事物后,需要用到子线程(例子中的1#、2#、5#)的处理结果才能继续做后续工作时,这是就可以用到join()方法。
五、interrupt()方法
interrupt()用于中断一个正在运行的线程对象;
interrupted()用于判断一个线程对象是否处于中断状态,若处于中断状态则清除中断状态,它是类方法。
isinterrupted()用于判断一个线程对象是否处于中断状态。
public class InterruptDemo extends Thread { private double d = 0.0; public InterruptDemo(String name) { super(name); } @Override public void run() { try { while (!Thread.interrupted()){ System.out.println("I 'm running!"); //让线程休眠20毫秒 Thread.sleep(20); System.out.println("Calculating..."); for (int i=0;i<1000;i++){ d = d + (Math.PI + Math.E)/d; } } } catch (InterruptedException e) { System.out.println("Exiting by Exception"); } System.out.println("run() of " + Thread.currentThread().getName() +" is interrupted!"); } } public class InterruptDriver { public static void main(String[] args) throws InterruptedException { //创建线程对象 InterruptDemo thread1 = new InterruptDemo("thread1"); thread1.start(); Thread.sleep(100); System.out.println("当前线程为" + Thread.currentThread().getName()); System.out.println("**********************"); System.out.println("Interrupted Thread!"); System.out.println("**********************"); thread1.interrupt(); } }
结果如下:在main方法中,初始化了thread1线程对象并启动了它,然后让主线程休眠100毫秒,thread1线程对象获取CPU使用权,运行InterruptDemo的run方法,“!Thread.interrupted()”为true,执行while循环中的逻辑,当主线程结束休眠,开始运行main方法中的逻辑。该例子把interrupt()和interrupt()方法结合使用,从而可以正常的中断程序的运行。
注意:(1)最后thread1线程对象不是通过interrupt()方法中断的,而是thread线程run()方法中调用了Thread.sleep(20)方法后,thread.interrupt()生效,然后while循环中判断条件“!Thread.interrupted()”为false,然后结束了线程。
(2)interrupt()方法不会直接中断一个正在运行的线程对象,而是在线程被阻塞时抛出一个中断信号,这样线程就得以退出阻塞状态。更具体一点,如果线程对象被wait()、join()、sleep()三种方法的任意一种阻塞,那么该线程对象将接受到一个中断异常,从而提前终结阻塞状态。如果线程没有被阻塞,调用interrupt()方法将不起作用。