Java多线程(四)——控制线程

来源:互联网 发布:下载社交软件 编辑:程序博客网 时间:2024/05/22 16:54
一、join线程
Thread提供了让一个线程等待另一个线程完成的方法——join()方法。当某个线程执行过程中调用其他线程的join()方法,该调用线程将被阻塞,直到被join()方法加入的join线程执行完为止。
使用join线程的一个情景:

在程序中将一个大问题分为许多小问题,每一个小问题分配一个线程。当所有的小问题都得到处理后,再调用主线程来进一步操作。

public class MainPrj {public static void main(String[] args){for(int i=0;i<100;i++){if(i==20){SubThread st=new SubThread("join线程");st.start();try {//main线程调用了st线程的join方法之后,main线程//必须要等到st执行结束后才会向下执行st.join();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println(Thread.currentThread().getName()+";"+i);}}}class SubThread extends Thread{private int i=0;public SubThread(String name){super(name);}@Overridepublic void run() {for(;i<100;i++){System.out.println(Thread.currentThread().getName()+";"+i);}}}
运行示例:


join()方法的3种重载形式:
1、join():等到被join线程执行完成。
2、join(long millis):等待被join的线程的时间最长为millis毫秒。如果在millis毫秒内被join线程没有执行完成,则不再等待。
3、join(long millis,int nanos):等到被join线程的时间最长为millis加上nanos毫微秒,使用频率不高。

二、后台线程

后台线程是在后台运行的,它的任务是为其他线程提供服务。调用线程的setDeamon(true)方法将指定线程设置为后台线程。

特征:

1、setDeamon()方法必须在start()方法之前调用。

2、如果所有的前台线程都死亡,后台线程会自动死亡。

3、isDeamon()方法判断指定线程是否是后台线程。

4、main线程默认是前台线程。由前台线程创建的子线程默认是前台线程,后台线程创建的线程默认是后台线程。

三、线程睡眠:sleep

Thread类的静态方法sleep()可以让当前正在执行的线程暂停一段时间。sleep()方法有两种重载的方法:

sleep(int millis)和sleep(int millis,int nanos)。由于受到系统计时器和线程调度器的精度与准确度影响,第二种方法很少用。

线程调用sleep()方法进入阻塞状态后,在阻塞时间内不会获得执行的机会,即使系统中没有其他可执行的线程,该阻塞线程也不会执行。

四、线程让步:yield

yield()方法和sleep()方法有点类似,它可以让线程暂停,但不会阻塞线程,而只是让线程转入就绪状态。当线程调用yield()方法暂停之后,只有优先级与当前线程相同,或者优先级更高的处于就绪状态的线程才会获得执行的机会。

public class MainPrj {public static void main(String[] args){SubThread st1=new SubThread("高级");//①设置st1的优先级//st1.setPriority(Thread.MAX_PRIORITY);st1.start();SubThread st2=new SubThread("低级");//②设置st2的优先级//st2.setPriority(Thread.MIN_PRIORITY);st2.start();}}class SubThread extends Thread{private int i=0;public SubThread(String name){super(name);}@Overridepublic void run() {for(;i<40;i++){System.out.println(Thread.currentThread().getName()+";"+i);if(i==20){Thread.yield();//当i=20时,当前线程让步}}}}
在注释掉①和②两句代码后,高级和低级两个线程的优先级是相同的,运行结果:



如果去掉两句的注释后,运行结果:


上面的运行结果可以清楚的看到yield()方法的作用。当然,根据系统的调度情况,每次运行的结果会不同,完全有可能优先级高的线程调用yield()方法后就让步给优先级低的线程了。

关于sleep()方法和yield()方法的区别如下:

1、sleep()方法暂停当前线程后,会给其他线程执行机会,不会理会其他线程的优先级;但是yield()方法只会给优先级相同或者优先级更高的线程。(这一点和我观察到的结果有出入啊:明明有的时候优先级高的线程调用yield()方法后,会马上执行优先级低的线程)。

2、sleep()方法会将线程转入阻塞状态,直到经过阻塞时间才会转入到就绪状态;而yield()不会将线程转入阻塞状态,它只是强制当前线程进入就绪状态。因此完全有可能某个线程调用yield()方法暂停之后,立即再次获得处理器的资源被执行。

3、sleep()方法声明抛出InterruptedException异常,所以调用sleep()方法要处理异常;而yield()方法没有声明抛出异常。

4、sleep()方法比yield()方法有更好的可移植性,通常不建议使用yield()方法来控制并发线程的执行。

五、改变线程优先级

Thread类提供了setPriority(int newPriority)和getPriority()方法设置和返回指定线程的优先级,其中setPriority()方法参数可以是一个整数,范围是1-10之间,也可以使用Thread提供的三个常量:

MAX_PRIORITY::其值是10;

MIN_PRIORITY:其值是1;

NORM_PRIORIRY:其值是5;

说明:

1、setPriority()方法和getPriority()方法都是普通方法,不是静态方法;

2、每个线程默认的优先级别和创建它的父线程的优先级相同,默认情况下main线程具有普通优先级,由main线程创建的子线程也具有普通优先级;

3、由于操作系统上支持的优先级不同,所以尽量避免直接为线程指定优先级,而应该使用MAX_PRIORITY、MIN_PRIORITY、NORM_PRIORIRY常量设置优先级。

0 0