Java多线程 – 控制线程

一、join线程

  像人类社会,人有很多时间都在等别人,线程也是一样,有的时候,线程也需要等待别的线程。Thread提供了让一个线程等待另一个线程完成的方法,那就是 join方法,当在某个程序执行流中调用其他线程的join()方法,调用线程则会被阻塞,知道join()方法加入的join线程执行完成为止。
  join()方法通常由使用线程的程序调用,以将大问题划分成许多小问题,每个小问题分配一个线程,当所有小问题都得到处理之后,在再调用主线程进一步进行操作。

class demo{
    public static void main(String[] args) throws InterruptedException {
        MyThread myThread = new MyThread();
        myThread.start();
        for(int  i = 0; i < 100; i++){
            if(i == 20){
                MyThread myThread1 = new MyThread();
                //main线程调用了myThread1线程中的join的方法,所以main线程必须等到其执行结束之后才能执行。
                myThread1.start();
                myThread1.join();
            }

            System.out.println(Thread.currentThread().getName());
        }

    }
}

class MyThread extends Thread{
    private int i;

    @Override
    public void run(){
        for(int i = 0; i < 100; i++){
            System.out.println(Thread.currentThread().getName() + " " + i);
        }
    }
}

  本程序之中有三个线程在运行,其中main线程在一开始就调用了myThread线程,所以它与main是并发执行,但是main线程调用了myThread1线程的join方法,所以他不会与main线程并发执行,而是直到其运行结束。

  其中join()方法有三种重载:

  1. join():等待join的线程运行结束。
  2. join(long millis):等待join线程的时间最长为millis秒,在millis毫秒之内还未执行结束,则不再等待。
  3. join(long millis, int nanos):等待join线程的时间最长为millis毫秒加nanos毫微妙。

二、后台线程

  有一类线程,他是在后台运行,任务是为了其他线程提供服务的,这类线程成为“后台线程”,也成为“守护线程”或者“精灵线程”,其中在JVM中,垃圾回收线程就是最典型的后台线程。
  后台线程的特征:如果所有的前台线程都死亡,则后台线程会自动死亡。
  设置方法:调用Thread对象的setDaemon(true)方法可以将指定线程设置为后台线程,当所有前台的线程都死亡的时候,后台线程的存在也没有用处了,此时后台进程也没有继续运行下去的必要了,所以程序也截止了。

  注意:前台线程死亡之后,JVM会通知后台线程死亡,但是从它接收指令再到做出指令,需要一定时间,且将某个线程设置为后台线程,需要再线程启动之前设置,也就是说需要再setDaemon(true)必须要在start()方法之前调用,否则会引发IllegalThreadStateException异常。

三、线程睡眠Sleep()

  如果需要当前执行的线程暂停一段时间,进入阻塞状态,则可以调用Thread类的静态方法sleep()方法来实现。
  > static void sleep(long millis):让当前正在执行线程暂停millis毫秒,并且进入阻塞状态,该方法收到系统计时器和线程调度器的精度和准确度影响。
  > static void sleep(long millis, int nanos):让正在执行的线程暂停millis毫秒加nanos毫微妙,并且进入阻塞状态,该方法收到系统计时器和线程调度器的精度和准确度影响。

  当线程调用阻塞状态后,在其睡眠时间端内,线程不会获得执行的机会,即使此时系统中没有其他的可执行线程,处于sleep()的线程也不会影响。

  此外,Thread还提供了一个与sleep()方法类似的yield()静态方法,也可以让当前的程序暂停,但是却不会阻塞线程,知识将线程转为就绪状态,。yield()只是将当前线程暂停一下,让系统的线程调度器重新调度一下,完全可能的情况是,当某个线程调用该方法暂停之后,线程调度器又将其调度出来重新执行。
  实际,线程调用yield()暂停之后,只有优先级与当前线程相同,或者优先级比当前线程更高的处于就绪状态的线程才会获得执行的机会。

sleep()方法和yield()方法区别:

  1. sleep()方法将暂停当前线程之后,给其他线程执行机会,不会理会其他线程的优先级;yield()方法只会给优先级相同,或者优先级更大的线程执行机会。
  2. sleep()方法会将线程转入阻塞状态,知道经过阻塞时间,才会转入就绪状态,yield()方法强制当前线程直接进入就绪状态。很可能某线程被转入就绪状态之后,立即再次获取处理器资源被执行。
  3. sleep()方法声明跑出InterruptedException异常,butyield()方法并未声明跑出任何异常。
  4. sleep()方法比yield()方法有更加好的可移植性,但是通常不建议使用yield()方法来控制并发线程的执行。

四、改变线程优先级

  每个线程都会拥有一定的优先级,优先级高的线程获得较多的执行机会,优先级低的线程则获得较少的执行机会
  每个线程的优先级默认与创建它的父线程优先级相同,默认情况:main线程拥有普通优先级。
  Thread类提供了setPriority(int newPriority)getPriority()方法设置和返回线程的优先级,优先级范围是1-10。

静态常量名


MAX_PRIORITY

10

MIN_PRIORITY

5

NORM_PRIORITY

1