并发编程使我们可以将程序划分为多个分离的,独立运行的任务。通过使用多线程机制,这些独立任务(也被成为子任务)中的每一个都将由执行线程来驱动。在使用线程时,CPU将轮流给每个任务分配其占用时间。每个任务都觉得自己在一直占用CPU,但事实上CPU时间是划分成片段分配给了所有的任务。
定义任务
线程可以驱动任务,因此我们需要一种描述任务的方式,实现Runnable接口并编写run()方法即可定义任务。例如下面的显示代码:
package com; /** * 类LiftOff.java的实现描述:显示发射之前的倒计时 * * @author wql 2016年9月21日 下午1:46:46 */ public class LiftOff implements Runnable { public LiftOff(){ taskCount++;//计数自增 } private int countDown = 3; // 倒计时数字 private static int taskCount = 0; private int id = taskCount; @Override public void run() { while (countDown >= 0) { System.out.println("线程编号" + id + "--倒计时" + countDown); countDown--; Thread.yield();
} } }
//Thread.yield()的调用是对线程调度器的一种建议,声明自身已完成重要的部分,可将程序切换给其他任务执行。
此时可以直接用main方法调用run(),但这种方式并不会产生任何线程能力,就像你调用一个普通的类方法一样。
package com; public class Main { public static void main(String[] args) { LiftOff liftOff = new LiftOff(); liftOff.run(); System.out.println("end"); } }
输出:
线程编号0--倒计时3 线程编号0--倒计时2 线程编号0--倒计时1 线程编号0--倒计时0 end
驱动任务
将Runnable对象转变为工作任务的方式是把它提交给一个Thread构造器:
package com; public class Main { public static void main(String[] args) { Thread t = new Thread(new LiftOff()); t.start(); System.out.println("end"); } }
输出:
end 线程编号0--倒计时3 线程编号0--倒计时2 线程编号0--倒计时1 线程编号0--倒计时0
通过调用Thread的start()方法启动任务,此时LiftOff.run()由一个新的线程执行,程序的main()方法也是一个线程,因此,程序会“同时”运行两个方法,我们看到“end”先被输出。
我们可以很容易添加更多的线程去驱动更多的任务:
package com; public class Main { public static void main(String[] args) { for (int i = 0; i < 3; i++) { new Thread(new LiftOff()).start(); } System.out.println("end"); } }
输出:
线程编号0--倒计时3 线程编号2--倒计时3 end 线程编号1--倒计时3 线程编号2--倒计时2 线程编号2--倒计时1 线程编号2--倒计时0 线程编号0--倒计时2 线程编号0--倒计时1 线程编号0--倒计时0 线程编号1--倒计时2 线程编号1--倒计时1 线程编号1--倒计时0
输出说明不同任务的执行在线程被切换时混在了一起,而每一次的输出结果可能会完全不同,因为线程调度机制是非确定性的。