Concurrency: Basic Threading (2)

5. Sleep

  Sleep()可以在指定时间内阻塞当前任务的执行。

这里使用了Java SE 5中引入的TimeUnit,显式地指明了时间单位MILLISECONDS,具有更好的可读性。这里在run()中捕获sleep()抛出的InterruptedException,异常不会跨线程传递,需要在抛出异常的任务中就地处理。

  从打印可以看到,上面例子中各个任务的运行比之前没有sleep()的版本更加规律,每个线程都进行过一次倒数,才会开始下一轮,因为打印输出后的sleep()会阻塞当前任务,使得任务调度器切换到其他线程的任务去执行。但不同平台的线程调度机制会有不同,不能依靠这种方式来控制任务的运行顺序。

6. Priority

  线程的优先级代表了线程对于调度器的重要程度,调度器会倾向于优先运行具有到优先级的线程,相比之下,低优先级的线程会运行地较少,但不代表低优先级的线程完全不会被运行。绝大多数情况下,所有线程都应该以默认优先级运行,尽量不要修改线程的优先级。

  可以通过getPriority()setPriority()获取和修改线程的优先级。

这里通过Thread.currentThread()获取当前线程的引用,在run()的开头设置线程的优先级,而不要在构造器中设置优先级(因为构造器执行的时候,ExecutorService还没有执行任务)。从打印可见,最晚执行的线程具有最高的优先级,会获得更多的执行。

  为了更明显地体现任务优先级,run()中包含了一段耗时的运算,这段运算会被调度器打断来进行任务切换,具有高优先级线程上的任务会更容易得到执行。

  JDK具有10个优先级,但不同操作系统也有各自的定义,Windows有7个不固定的优先级,Solaris有231个优先级。为了在不同系统上获得相同的效果,可以使用MAX_PRIORITYNORM_PRIORITYMIN_PRIORITY

7. Yielding

  在当前任务完成了阶段性的工作后,可以使用yield()可以向调度器建议切换到其他线程。注意yield()只是建议,不能对线程的切换进行可靠地控制。

  前面一直使用的LiftOff在打印后调用了Thread.yield(),来让各个任务获得平均的运行机会。如果注释掉LiftOff里的Thread.yield(),再运行MoreBasicThreads,就会发现各个任务的执行顺序变得更加随机:

8. Daemon threads

  Daemon线程(守护线程)用于在后台为程序提供长期的服务,只要程序还在运行,Daemon线程就会一直存在。当所有的非Daemon线程完成时,程序结束,进程中的所有Daemon线程就会被杀掉。

8.1. 设置Daemon线程

8.1.1. 使用Thread

  要设置一个线程为Daemon线程,必须在线程开始(start())前调用setDaemon(true)

上面的代码在main()中进行了一段sleep(),期间可以看到Daemon线程的打印。之后main()结束,程序结束,所有Daemon线程都被杀掉。

8.1.2. 使用ThreadFactory

  上面的例子显式地创建了Thread对象,并通过Thread对象的引用来设置它为Daemon线程。使用Executors的时候,无法直接接触Thread对象,这时可以通过ThreadFactory来为Executors创建并配置线程。

  然后就可以使用DaemonThreadFactory作为Executors.newCachedThreadPool()的参数,来为Executors创建特定配置的Thread

除了这里使用的newCachedThreadPool()Executors创建ExecutorService的所有静态方法都有接受ThreadFactory的重载。

8.1.3. 使用ThreadPoolExecutor

  还可以更进一步地继承ThreadPoolExecutor,实现专门创建特定线程的ThreadPoolExecutor

8.2. 判断Daemon线程

  使用isDaemon()可以检查一个线程是否为Daemon线程。在Daemon线程中创建的线程都会自动成为Daemon线程。

8.3. Daemon线程的结束

  需要注意的是,Daemon线程的run()结束时,不会执行finally下的内容。

由上面的例子可见,finally下的内容没有运行。注释掉t.setDaemon(true),就可以看到finally下打印了。

  当main()结束时,JVM会立即结束所有的Daemon线程,由于Daemon线程无法以常规的方式结束,非Daemon线程通常会是更好的选择。