本文正在参加「Java主题月 - Java 刷题打卡」,详情查看活动链接
创建线程两种方式:
- 继承自
Thread类
继承
Thread,重写方法run()
public class MyThread extends Thread{
public void run() {}
}
- 实现
Runnable接口
推荐使用 实现
run方法,符合里氏代换原则
public class MyThread implements Runnable {
public void run() {}
}
start()与run()区别:
start()方法来启动线程,真正实现了多线程运行。这时无需等待
run方法体代码执行完毕,可以直接继续执行下面的代码;通过调用Thread类的start()方法来启动一个线程, 这时此线程是处于就绪状态, 并没有运行。 然后通过此Thread类调用方法run()来完成其运行操作的, 这里方法run()称为线程体,它包含了要执行的这个线程的内容,Run方法运行结束, 此线程终止。然后CPU再调度其它线程。
run()方法当作普通方法的方式调用。程序还是要顺序执行,要等待
run方法体执行完毕后,才可继续执行下面的代码; 程序中只有主线程——这一个线程, 其程序执行路径还是只有一条, 这样就没有达到写线程的目的。
应用如下:
public class Test {
public static void main(String[] args) {
Thread thread1 = new Thread(new Runner1());
Thread thread2 = new Thread(new Runner2());
// thread1.start();
// thread2.start();
thread1.run();
thread2.run();
}
}
// 实现了Runnable接口,jdk就知道这个类是一个线程
class Runner1 implements Runnable {
public void run() {
for (int i = 0; i < 2; i++) {
System.out.println("进入Runner1运行状态——————————" + i);
}
}
}
// 实现了Runnable接口,jdk就知道这个类是一个线程
class Runner2 implements Runnable {
public void run() {
for (int i = 0; i < 2; i++) {
System.out.println("进入Runner2运行状态==========" + i);
}
}
}
Tips:
- 其实
Callable和Future本身并不能产生新的线程,它们需要借助其他的比如Thread类或者线程池才能执行任务。Thread里源码注释也只写了两种方式。
- 实现
Callable接口
前面两种,在任务执行完成后,无法直接获取执行结果,需要借助共享变量等来获取。
Callable和Future则很好地解决了这个问题异常:
call()可以抛出异常。Runnable只有通过setDefaultUncaughtExceptionHandler()的方式才能在主线程中捕捉到子线程异常
public class MyThread implements Callable<Integer> {
@Override
public Integer call() throws Exception {
return 1;
}
}