多线程的实现方式
1.1方式一:继承Thread类【应用】
- 实现步骤
- 定义一个类MyThread继承Thread类
- 在MyThread类中重写run()方法
public class Mythread extends Thread {
@Override
public void run() {
// 代码就是线程在开启后执行的代码
// 快捷键 100.fori 回车
for (int i = 0; i < 100; i++) {
System.out.println("线程开启了"+i);
}
}
}
- 创建MyThread类的对象
- 启动线程
public class Demo {
public static void main(String[] args) {
//创建一个线程对象
Mythread t1 = new Mythread();
//创建一个线程对象
Mythread t2 = new Mythread();
//开启一个线程
t1.start();
//开启第二个线程
t2.start();
//没有开启线程,按顺序执行
t1.run();
t2.run();
}
}
- 运行结果
-
两个小问题
-
为什么要重写run()方法?
因为run()是用来封装被线程执行的代码
-
run()方法和start()方法的区别?
run():封装线程执行的代码,直接调用,相当于普通方法的调用,没有开启线程
start():启动线程;然后由JVM调用此线程的run()方法
-
1.2方式二:实现Runnable接口【应用】
-
实现步骤
- 定义一个类MyRunnable实现Runnable接口
- 在MyRunnable类中重写run()方法
public class MyRunnable implements Runnable {
@Override
public void run() {
//线程启动后执行的代码
for (int i = 0; i < 100; i++) {
System.out.println("线程开启"+i);
}
}
}
- 创建MyRunnable类的对象
- 创建Thread类的对象,把MyRunnable对象作为构造方法的参数
- 启动线程
public class Demo {
public static void main(String[] args) {
//创建一个参数对象
MyRunnable myRunnable1 = new MyRunnable();
//myRunnable.start 没有start方法
//创建一个线程Thread对象,把myRunnable作为参数传递进去
Thread t1 = new Thread(myRunnable1);
//线程启动后就执行的是参数里面的run方法
t1.start();
MyRunnable myRunnable2 = new MyRunnable();
Thread t2 = new Thread(myRunnable2);
t2.start();
}
}
- 运行结果
1.3方式三: 实现Callable接口【应用】
-
实现步骤
- 定义一个类MyCallable实现Callable接口
- 在MyCallable类中重写call()方法
public class MyCallable implements Callable<String> {
@Override
public String call() throws Exception {
//返回值表示线程运行之后返回的结果Callable<Object> 泛型就是返回值得类型
for (int i = 0; i < 100; i++) {
System.out.println("跟女孩表白"+i);
}
return "答应";
}
}
-
创建MyCallable类的对象
-
创建Future的实现类FutureTask对象,把MyCallable对象作为构造方法的参数
-
创建Thread类的对象,把FutureTask对象作为构造方法的参数
-
启动线程
-
再调用get方法,就可以获取线程结束之后的结果。
-
代码演示
public class Demo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//创建MyCallable对象
MyCallable myCallable1 = new MyCallable();
//可以获取线程执行完毕的结果,也可以作为参数传递给Thread对象
FutureTask<String> futureTask = new FutureTask<>(myCallable1);
//创建对象开启线程
Thread t1 = new Thread(futureTask);
//String s = futureTask.get();
t1.start();
//获取线程的返回结果
// get()方法需要在线程开启后执行,如果线程运行还没有结束,get方法会在这里死等
String s = futureTask.get();
System.out.println(s);
}
}
- 运行结果
1.4 三种实现方式的对比
- 实现Runnable、Callable接口
- 好处: 扩展性强,实现该接口的同时还可以继承其他的类
- 缺点: 编程相对复杂,不能直接使用Thread类中的方法
- Callable接口可以获取线程的返回值
- 继承Thread类
- 好处: 编程比较简单,可以直接使用Thread类中的方法
- 缺点: 可以扩展性较差,不能再继承其他的类