1. 继承Thread 类实现多线程
想要实现多线程,第一种方法就是通过继承Thread类实现多线程,有以下几步
(1)我们要先自定义一个类然后继承Thread类;
(2)在继承Trread的类中重写 run 方法;
(3)通过创建该类的对象即可创建线程,创建多个对象就可以实现多线程;
(4)这种实现多线程的方式无法获取多线程的结果;
如下代码,我先定义了一个ThreadTest01类
// 创建一个类继承 Thread 类
public class Thread01 extends Thread{
// 重写 run 方法
@Override
public void run(){
for (int i = 0; i < 5; i++) {
// 通过getName() 获取线程名称
System.out.println(getName()+"多线程");
}
}
}
我们在另一个类中写一个 main 方法,创建 ThreadTest01类的对象,然后就可以实现多线程,代码如下;
public class TestThread01 {
public static void main(String[] args) {
// 创建线程 t1
Thread01 t1 = new Thread01();
// 创建线程 t2
Thread01 t2 = new Thread01();
// 给 t1 线程添加一个名字做区分
t1.setName("线程1");
// 给 t2 线程添加一个名字做区分
t2.setName("线程2");
// 通过 start 启动线程
t1.start();
t2.start();
}
}
运行上述 main 方法,即可在在控制台中得到如下结果
我们可以看到,线程1与线程2交替执行,最终都进行完成,这就做到了多线程的效果。
2. 实现 Runnable 接口的方式实现多线程
通过实现 Runnable 接口的方式实现多线程也大致可以分为以下几步
(1)自定义一个了类实现 Runnable 接口;
(2)重写 run 方法;
(3)创建自定义类的对象;
(4)创建 Thread 类对象,将自定义对象作为参数传递给 Thread对象;
(5)通过调用 start 方法启动线程实现多线程;
(6)这种实现多线程的方式也无法获取多线程的结果。
代码如下所示,首先先定义一个自定义类实现 Runnable 接口,重写run方法。
// 创建一个类实现 Runnable 接口
public class Thread02 implements Runnable{
// 重写 run 方法
@Override
public void run(){
for (int i = 0; i < 5; i++) {
/**
* 这里有一个点需要注意,刚才我们通过继承 Thread 实现多线程,
* 之所以可以通过 getName()方法获取线程名称,是因为getName()方法时 Thread 类中的,
* 子类可以直接使用父类中的方法。
* 但现在我们是实现 Runnable 接口实现多线程,就不能也无法直接调用 getName() 方法获取线程名称
* 但我们可以再创建一个 Thread 类的对象,接收当前线程对象
* 然后再使用 getName() 方法获取当前线程对象名称
* 这一点需要注意哦!!!
*/
// 创建对象 t 获取当前线程对象
Thread t = Thread.currentThread();
// 获取当前线程名称
System.out.println(t.getName() +"多线程");//getName()
}
}
}
然后去另一个测试类写 main 方法测试多线程,代码如下
public class TestThread02 {
public static void main(String[] args) {
// 创建线程 Thread02的对象
Thread02 t1 = new Thread02();
// new 一个线程,将 t1 作为参数传递进去
Thread thread01 = new Thread(t1);
// 创建线程 thread02 的对象
Thread02 t2 = new Thread02();
// 再 new 一个线程,将 t2 作为参数传递进去
Thread thread02 = new Thread(t2);
// 给 t1 线程添加一个名字做区分
thread01.setName("线程1");
// 给 t2 线程添加一个名字做区分
thread02.setName("线程2");
// 通过 start 启动线程
thread01.start();
thread02.start();
}
}
运行 main 方法,即可在控制台得到如下结果,因为我循环次数较少,可能效果不明显,各位小伙伴自行测试的时候可以把 for 循环次数增多,会更加直观一些!
3. 利用 Callable 和 Future 接口实现多线程
其实这第三种方式是对前两种实现多线程方式的补充,我们可以发现,前两种方法实现多线程时,重写 run 方法,返回值都是 viod ,因此无法获取多线程的执行结果,而这第三种方法就可以。
大致分为以下几步
(1)创建一个自定义类实现 Callable 接口;
(2)重写 call ,(有返回值的,表示多线程的运行结果);
(3)创建自定义类的对象,执行要执行的任务;
(4)创建 Future 的对象,它可以管理多线程运行的结果,但是 Future 是一个接口,所以我们需要创建它的是实现类 FutureTask 的对象。
(5)创建 Thread 的对象,并调用 start 启动线程。
先创建一个类实现 Callable 接口,如下代码所示
// 创建一个类实现 Callable 接口,这里要注意,Callable需要传递一个泛型,表示运行的结果类型
public class Thread03 implements Callable<Integer> {
@Override
public Integer call() throws Exception {
// 随便写一段逻辑,求 1~100 的 整数和
int sum = 0;
for (int i = 1; i <= 100; i++) {
sum = sum + i;
}
// 将计算的结果返回
return sum;
}
}
我们去另一个类编写 main 方法测试这种带有返回值的多线程的方法,代码如下所示
public class TestThread03 {
public static void main(String[] args) {
// 创建线程 Thread03的对象
Thread03 t1 = new Thread03();
// 将创建的 t1 对象作为参数传递给 FutureTask
FutureTask<Integer> futureTask = new FutureTask<>(t1);
// 创建 Thread 对象,并把 futureTask 作为参数的传递进去
Thread thread = new Thread(futureTask);
// 通过 start 启动线程
thread.start();
// 获取线程的结果,有异常使用 try。。。catch。。。
try {
Integer num = futureTask.get();
System.out.println(num);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
运行 main 方法,即可在控制台得到1~100 的结果,如下所示
4. 总结概括
(1)实现多线程有三种方式,一是继承 Thread 类,二是实现 Runnable 接口,三是实现 Callable接口并利用 FutureTask 类接收线程结果。
(2)继承 Thread 类实现多线程不可以获取线程的结果;实现 Runnable 接口实现多线程的方式也无法获取返回值结果。
(3)我们都知道,继承只能单继承,而接口却可以多实现。
因此不难看出,第一种继承 Thread 类实现多线程的方式是不太友好地,虽然编程较为简单,但是可扩展性较差,一旦我们的业务类还需要继承别的类,就不行了。
而第二种与第三种方式,均是通过实现接口的方式来实现多线程的,也可以继承其他类实现其他接口,虽然编写过程较复杂,但可扩展性强,但是也无法直接使用 Thread 类中的方法了。