在java中要实现多线程,有两种手段,一种是继承Thread类,另外一种是实现Runable接口.(准确讲是三种,还有一种实现Callable接口,并与Future、线程池结合使用)
一、扩展java.lang.Thread类
- 定义类继承Thread
- 复写Thread类中的run方法
- 调用线程的start方法(此方法作用:启动线程,调用run方法)
-
package cn.demo; public class Thread1 extends Thread { private String name; public Thread1(String name){ this.name=name; } public void run(){ for (int i = 0; i < 5; i++) { System.out.println(name + "运行 : " + i); try { sleep((int) Math.random() * 10); } catch (InterruptedException e) { e.printStackTrace(); } } } } package cn.demo; public class test { public static void main(String[] args) { // TODO Auto-generated method stub Thread1 mth1=new Thread1("A"); Thread1 mth2=new Thread1("B"); mth1.start(); mth2.start(); } }
输出结果:
A运行 : 0 B运行 : 0 B运行 : 1 B运行 : 2 A运行 : 1 B运行 : 3 A运行 : 2 B运行 : 4 A运行 : 3 A运行 : 4
程序启动运行main时候,java虚拟机启动一个进程,主线程main在main()调用时候被创建。随着调用两个对象的start方法。另外两个线程也启动了。
多线程代码执行顺序是不确定的,每次执行的结果都是随机的。
二、实现java.lang.Runnable接口
- 定义类实现Runnable接口
- 覆盖Runnable接口中的run方法(将线程要运行的代码存放在该run方法中)
- 通过Thread类建立线程对象
- 将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数。(为什么要将Runnable接口的子类对象传递给Thread的构造函数。因为自定义的run方法所属的对象是runnable接口的子类对象。所以要让线程去指定指定对象的run方法,就必须明确该run方法所属对象)
- 调用Thread类的start方法开启你线程并调用Runnable接口子类的run方法
package cn.demo; public class Thread2 implements Runnable { private String name; public Thread2(String name){ this.name=name; } @Override public void run(){ for (int i = 0; i < 5; i++) { System.out.println(name + "运行 : " + i); try { Thread.sleep((int) Math.random() * 10); } catch (InterruptedException e) { e.printStackTrace(); } } } } package cn.demo; public class test { public static void main(String[] args) { // TODO Auto-generated method stub new Thread(new Thread1("C")).start(); new Thread(new Thread1("D")).start(); } }
输出结果:
C运行 : 0 D运行 : 0 C运行 : 1 D运行 : 1 C运行 : 2 D运行 : 2 C运行 : 3 D运行 : 3 C运行 : 4 D运行 : 4
实现方式和继承方式有什么区别?
实现方式好处:避免了单继承的局限性。在定义线程时,建议使用实现方式。区别:
继承Thread:线程代码存放Thread子类run方法中。
实现Runnable:线程代码存在接口的子类的run方法。