多线程创建的三种方式
- 继承Thread类
- 实现Runnable接口
- 实现Callable接口
第一种方式创建线程
Thread类,实现了Runnable接口
Runnable接口类
run() 调用线程
Thread类,作为Runnable的实现类,有父类的所有方法,同时有自身开启线程的方法start()
- 通过继承Thread类,创建一个新的线程类MyThread
- 重写Thread的run方法
- 将代码逻辑填写到run方法中
- 创建MyThread实例,调用Thread类的start方法,开启线程
注意:由于是线程类,如果进行测试,需要观察其执行顺序,在run方法和主线程main方法中都建议填写for循环,拉大执行的时间和次数,方便抢占CPU
public class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("MyThread 执行了" + i + "次");
}
}
}
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();
for (int i = 0; i < 10; i++) {
System.out.println("主线程执行了" + i + "次");
}
}
第二种方式创建线程
- 创建MyRunnable类,实现Runnable接口,重写run方法;
- 在run方法中填写代码逻辑
- 利用Thread类的构造方法,将Runnable的实例作为参数,创建Thread对象
- 通过Thread实例调用start方法
public class MyRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + "执行了" + i + "次");
}
}
}
public static void main(String[] args) throws InterruptedException {
MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable);
thread.start();
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + "执行了" + i + "次");
}
}
也可以通过匿名类的方式去创建
Thread thread = new Thread(Runnable runnable);
我们可以通过以上方式来创建一个Thread实例,但是Runnable是一个接口,匿名类即当场写出其抽象方法;
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + "执行了" + i + "次");
}
}
});
thread.start();
}
// 当然,也可以用链式调用,new Thread()返回一个Thread对象,那么可以直接调用start()方法
第三种方式创建线程、
public class MyCallable implements Callable<String> {
@Override
public String call() throws Exception {
return "hello";
}
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
MyCallable myCallable = new MyCallable();
FutureTask<String> stringFutureTask = new FutureTask<>(myCallable);
new Thread(stringFutureTask).start();
String s = stringFutureTask.get();
System.out.println(s);
}
线程创建问题归纳和注意点:
问题:如果直接调用run方法,而不是start方法,会出现什么情况?
如果直接使用MyThread实例调用run方法,只是相当于调用了一个方法, 并不是开启线程,所以会从上往下执行。run方法执行完毕,才会向下执行。
注意:
- 每一次调用start方法,都会开辟一个新的栈空间,在这个栈空间中去执行新线程中的run方法
- 一个对象,只能调用一次start方法,调用多次会报错;就算主线程发生报错,前面已经开启start的线程方法仍然会执行完毕