java多线程--1
线程创建的方式
1.Thread对象
1.1 继承Thread对象
@Slf4j
public class MyThread extends Thread{
@Override
public void run() {
// 线程要执行的内容
log.debug("继承Thread方式");
}
}
public class Test1 {
public static void main(String[] args) {
new MyThread().start(); // 启动线程
}
}
1.2 直接使用Thread对象
public class Test1 {
public static void main(String[] args) {
Thread t = new Thread(){
@Override
public void run() {
log.debug("线程执行");
}
};
t.start();
}
}
2.Runnable接口
public class MyThread implements Runnable{
@Override
public void run() {
// 该线程执行内容
System.out.println("线程执行");
}
}
public static void main(String[] args) {
MyThread myThread = new MyThread();
Thread t1 = new Thread(myThread, "t1");
t1.start();
// jdk8 Lambda
Thread t2 = new Thread(()->{ System.out.println("t2执行");}, "t1");
t2.start();
Runnable runnable = ()->{ System.out.println("t3执行"); };
Thread t3 = new Thread(runnable, "t3");
t3.start();
}
3.Runnable和Thread的关系
Runnable的运行需要传入Thread中执行
Runnable runnable = ()->{ System.out.println("t3执行"); };
Thread t3 = new Thread(runnable, "t3");
t3.start();
点开Thread源码发现会把Runnable传个init方法
发现init又传给另外一个init
该init方法中发现他又传给了自身的一个变量
发现在Thread类中的run()方法最终调用了这个Runnable的run方法
Runnable的run最终还是走的Thread的run,如果不重新run方法的情况下Thread的run方法会优先判断是否有Runnable传入,如果有那么就执行Runnable的run方法
3.Callable和FutureTask
FutureTask本身实现RunnableFuture
public class FutureTask<V> implements RunnableFuture<V>
RunnableFuture 又多继承了Runnable和Future
public interface RunnableFuture<V> extends Runnable, Future<V>
也就是说FutureTask也可以看做一个Runnable但是又强于Runnable
因为还继承了Future中的方法赋予了它获取线程运行结果的能力
Callable只是一个接口其call 和 Runnable的run方法性质差不多,都是线程要运行其中的代码,但call有返回值的泛型同时也能做异常的抛出,run方法就不具备异常也得内部自己消化
但我们运行代码的时候还是用的 start方法其还是去跑run方法,但发现我们这里并没有重写run方法而是一个call方法
点开FutureTask 类,发现其内部重写了run方法,当我们在start启动线程的时候该run方法会去调用其传入的Callable的call方法,并在这里做了异常的处理并在这个时候把值返回给FutureTask的set方法供get等方法的调用
值返回给变量outcome
调用get方法的时候调用其report方法
该方法的返回就是run方法调用call的值
注意
看到get方法有返回值,也就是说他会一直阻塞到线程异步的返回