控制线程

来源:互联网 发布:mac sdk manager 编辑:程序博客网 时间:2024/05/16 06:17

  java的线程支持提供了一些便捷的工具方法,通过这些工具方法我们可以很好的控制线程的执行。

        线程睡眠:sleep

       如果我们需要让当前正在执行的线程暂停一段时间,并进入阻塞状态,就可以通过调用Thread类的静态sleep方法,sleep方法有两种重载形式:

               1.static void sleep(long millis):让当前正在执行的线程暂停millis毫秒,并进入阻塞状态。

               2.static void sleep(long mills,int nanos)):让当前正在执行的线程暂停millis毫秒加nanos微秒,并进入阻塞状态。一般我们很少用到这个方法,因为程序对时间的计算无法精确到微秒,计算机硬件、操作系统也无法精确到微秒。

        当当前线程调用sleep方法进入阻塞状态后,在其sleep时间内,该线程将不会再有获得执行的机会,即使系统中没有其他正在执行的线程,处于sleep线程也不会运行。因此,sleep方法常用来暂停程序的执行。

  上面这段程序中只有一个线程,当主线程进入sleep以后,系统没有可执行的线程,所以可以看到线程在sleep处暂停。

  sleep方法只是让当前线程暂停一段时间,给其他线程执行的机会,当时间到时,CPU资源又会重新分配。

       比如:

运行结果:

      线程让步:yield
      yield方法是一个和sleep方法有点相似的方法,它也是Thread类提供的一个静态方法,它也可以让当前正在执行的线程暂停,但它不会阻塞该线程,它只是将该线程转入就绪状态,然后让调度器重新调度一次。所以,很可能一个线程调用了yield方法之后,线程调度器又将其调出来重新执行。
    实际上,当某个线程调用了yield方法之后,只有具有相同优先级或更高优先级的就绪状态的线程可以获取执行的机会。下面程序使用yield方法暂停当前只在执行的线程:
  
其运行结果如下:
 
 
 
  
      由于设置优先级的代码被注释掉了,所以两条线程的优先级相同,即

       但是,有时候,某一个线程要等另外一个线程执行完毕以后再执行,比如:你正正在在线看电影,外面有人送外卖,你应该先暂停一下电影,然后去开门,接外卖,付款。开门,接外卖,付款这应该是一个连续的过程,你不能打开门,看会电视,再回接外卖,再看会电影,再付款吧。所以,你看电影的线程要等外卖线程执行完成以后才可以继续执行。这就要用到join方法。

        join方法:让一个线程等待另一个线程,当在某个程序执行流中调用其他线程的join方法是,调用线程将会被阻塞,知道被join方法加入的join线程完成为止。我们先来看一段代码:

   

 

        由于设置优先级的代码被注释掉了,所以这两个线程的优先级是一样的,当一条线程调用yield方法暂停之后,这两个线程都有可能被调度。但是如果把注释部分取消,那么就只有高级线程才可以被调度。

       这里提一下优先级吧。每一个线程都有一个优先级。毫无疑问,优先级高的线程将获得更多的执行机会,而优先级低的线程则获得较少的执行机会。每个线程默认的优先级都与创建它的线程的优先级相同。在默认情况下,main方法拥有普通优先级,所以,由它创建的线程也拥有普通优先级。Thread提供了setPriority和getPriority方法设置和返回优先级。我们通常用MAX_PRIORITY、NORM_PRIORITY、MIN_PRIORITY三个静态常量来表示高、中、低三个不同的优先级。

        关于sleep和yield方法,二者的区别大致如下:

        1.sleep方法暂停当前线程后,会给其他线程执行机会,不会理会其他线程的优先级;但yield方法只会给优先级相同或更高的线程执行机会。

         2.sleep方法将线程转入阻塞状态,知道阻塞时间才会转入就绪状态;而yield方法不会将线程转入阻塞状态,它只是强制当前线程进入就绪状态。因此,完全有可能在调用yield方法之后,又被调度器调度执行。

         3.sleep方法声明抛出了InterruptedException异常,所以调用sleep方法是要么捕捉该异常,要么抛出该异常;而yield方法没有声明任何异常。

         4.sleep方法比ield方法有更好的可移植性,通常不需要yield方法来控制并发线程的执行。

      

  这段程序中一共有3条线程,主方法开始时就启动了名为“新线程”的子线程,该子线程将会和main线程并发执行。当主线程的循环变量i等于20时,启动了名为“被join的线程”的线程,该线程不会与主线程并发执行,而是main线程必须等该线程执行结束以后才可以向下执行。在名为“被join的线程”的线程执行时,实际上只有两条线程并发执行,而主线程处于等待状态。其运行结果如下:

  

  join方法有三种重载形式:

           1.join():等待被join的线程执行完毕

            2.join(long millis):等待被join的线程的最长时间为 millis毫秒,如果在millis毫秒内,被join的线程还没有被执行完毕也不再等待。

            3.join(long millis,int nanos):):等待被join的线程的最长时间为 millis毫秒加上nanos微秒。与前面类似,我们也很少调用这个方法。