1. Thread类的概念
<1> java.lang.Thread类代表线程,任何线程对象,都是Thread类(子类)的实例。
<2> Thread类是线程的模板,封装了复杂的线程开启等操作,封装了操作系统的差异性
2. 线程的创建方式
<1>自定义类,继承Thread类,并重写run方法,然后创建该类的对象,调用start方法
<2>自定义类,实现Runnable接口,并重写run方法,创建该类的对象作为实参,来构造Thread类型的对象,
然后使用Thread类型的对象,调用start方法
3. 相关的方法
方法声明 | 功能介绍 |
Thread() | 使用无参的方式,构造对象 |
Thread(String name) | 根据参数指定的名称,来构造对象 |
Thread(Runnable target) |
根据参数指定的引用来构造对象,其中Runnable是个接口类型 |
Thread(Runnable target,String name) |
根据参数指定引用和名称,来构造对象 |
void run() |
若使用Runnable引用构造了线程对象,调用该方法时,最终调用接口中的版本 若没有使用Runnable引用构造线程对象,调用该方法时,则什么也不做 |
void start() |
用于启动线程,Java虚拟机会自动调用,该线程的run方法 |
4. 代码示例 1
1 class ThreadTest{ 2 main(){ 3 4 // 1. 使用无参方式,构造Thread类型的对象 5 // 由源码可知:Thread类中的成员变量target的数值,为null 6 Thread t1 = new Thread(); 7 8 // 2. 调用run方法进行测试 9 // 由源码可知:由于成员变量target的数值为null, 10 // 因此 if (target != null) 不成立, 跳过{}中的代码不执行 11 // 而run方法中,除了上述代码,再无其它代码,因此证明,run方法确实"啥也不干" 12 t1.run(); 13 14 // 3. 打印一句话 15 System.out.println("我想看看你到底是否真的啥也不干!"); 16 } 17 }
代码示例 2
1 class ThreadNoNameTest{ 2 main(){ 3 4 // 匿名内部类的语法格式: 父类/接口类型 引用变量名 = new 父类/接口类型(){方法的重写}; 5 // 1. 使用 继承 + 匿名内部类 的方式,创建并启动线程 6 /* 7 Thread t1 = new Thread(){ 8 @Override 9 public void run(){ 10 print("张三说:在吗?"); 11 } 12 }; 13 t1.start(); 14 */ 15 new Thread(){ 16 @Override 17 public void run(){ 18 print("张三说:在吗?"); 19 } 20 }.start(); 21 22 23 // 2. 使用 实现接口 + 匿名内部类 的方式创建,并启动线程 24 /* 25 Runnable ra = new Runnable(){ 26 @Override 27 public void run(){ 28 print("李四说:不在"); 29 } 30 }; 31 Thread t2 = new Thread(ra); 32 t2.start(); 33 */ 34 /* 35 new Thread(new Runnable() { 36 @Override 37 public void run(){ 38 print("李四说:不在"); 39 } 40 }).start();zhiqian 41 */ 42 43 // Java8开始,支持lambda表达式: (形参列表) -> {方法体;} 44 /* 45 Runnable ra = () -> print("李四说:不在"); 46 new Thread(ra).start(); 47 */ 48 new Thread( () -> print("李四说:不在") ).start(); 49 } 50 }
5. 执行流程
<1> 执行main方法的线程,叫做主线程,执行run方法的线程,叫做新线程/子线程
<2> main方法是程序的入口,对于start方法之前的代码来说,由主线程执行一次。
当start方法调用成功后,线程个数由1个变成2个,
新启动的线程去执行run方法的代码,主线程继续向下执行,两个线程各自独立运行、互不影响。
<3> 当run方法执行完毕后,子线程结束
当main方法执行完毕后,主线程结束
<4> 两个线程执行,没有明确的先后执行次序,由操作系统调度算法来决定
6. 线程创建方式的比较
<1> 继承Tread类的方式:代码简单,但是,若该类继承Thread类后,则无法继承其他类
<2> 实现Runnable接口的方式:代码复杂,但不影响该类继承其他类以及实现其他接口 (推荐)
<3> 不论使用方式<1>还是<2>,都可以使用匿名内部类来创建和启动线程