创建线程
方法一:Thread 类
创建Thread类的对象,重写其中的 run 方法:
@Slf4j(topic = "c.Test1")
public class d1_Thread {public static void main(String[] args) {// 创建 Thread 类的对象Thread t = new Thread(){@Overridepublic void run(){log.debug("running"); // t1 线程}};t.setName("t1");t.start();log.debug("running"); // main线程}
}
以继承的方式重写 run :
public class MyThread extends Thread{// 2. 重写Thread类的run方法@Overridepublic void run() {// 1. 描述线程的执行任务for (int i = 0; i < 5; i++) {System.out.println("son Thread output : " + i);}}
}public class ThreadTest1 {// main方法由一条默认的主线程负责执行public static void main(String[] args) {// 3. 创建MyThread线程类的对象代表一个线程Thread t = new MyThread();// 4. 启动线程(自动执行 run 方法)t.start();// 已经有两个线程了:main 线程, t线程// 它们这两个线程的输出没有前后for (int i = 0; i < 5; i++) {System.out.println("main Thread output : " + i);}}
}
注意实现:
- 启动子线程要调用start方法,而不是run方法,否则还是只有main线程
- 子线程任务要放在主线程之前,如果主线程在子线程之前,主线程任务就一定在子线程任务前
缺点:
- 线程类已经继承了Thread类,无法继承其他类,不利于扩展
方法二:Runnable接口与Thread类
创建Runnable接口的匿名内部类对象,重写其中的 run 方法
/*** Represents an operation that does not return a result.** <p> This is a {@linkplain java.util.function functional interface}* whose functional method is {@link #run()}.** @author Arthur van Hoff* @see java.util.concurrent.Callable* @since 1.0*/
@FunctionalInterface
public interface Runnable {/*** Runs this operation.*/void run();
}
其中 Runnable接口只有一个方法,被注解为 FunctionalInterface
,所以可以用 lambda表达式简化
@Slf4j(topic = "c.Test2")
public class d2_Runnable {public static void main(String[] args) {
// Runnable r = new Runnable() {
// @Override
// public void run() {
// log.debug("running");
// }
// };// lambda精简代码Runnable r = ()->log.debug("running");Thread t = new Thread(r, "t2");t.start();}
}
以继承接口的方式实现:
// 1. 定义一个任务类,实现Runnable接口
public class MyRunnable implements Runnable{// 2. 重写 Runnable接口的run方法@Overridepublic void run() {// 线程执行的任务for (int i = 0; i < 5; i++) {System.out.println("子线程输出:"+i);}}
}public class ThreadTest2 {public static void main(String[] args) {// 3. 创建任务类的对象Runnable target = new MyRunnable();// 4. 任务对象交给线程对象处理Thread thread = new Thread(target);thread.start();for (int i = 0; i < 5; i++) {System.out.println("主线程执行:" + i);}}
}
优点:任务类只是实现接口,可以继续继承其他类,实现其他接口,扩展性强
实现原理:
Runnable
对象会被赋值给 holder.task
变量,在 Thread
类的 run 方法中会判断是否存在 task
变量,如果存在则优先执行。
直接创建 Thread
对象,对其中的 run
方法重写,就等于覆盖了下面的方法。
@Overridepublic void run() {Runnable task = holder.task;if (task != null) {Object bindings = scopedValueBindings();runWith(bindings, task);}}
方法三:FutureTask接口获取 run 的返回值
实现:
- 创建
FutureTask
的对象,传入 Callable参数,泛型选择返回值类型,重写其中的call方法 - 将
FutureTask
对象传入 Thread 对象 - 调用
FutureTask
对象的 get 方法获取返回值
@Slf4j(topic = "c.Test3")
public class d3_FutureTask {public static void main(String[] args) throws Exception {
// FutureTask<Integer> task = new FutureTask<>(new Callable<Integer>() {
// @Override
// public Integer call() throws Exception {
// log.debug("running");
// Thread.sleep(1000);
// return 100;
// }
// });// 简化:FutureTask<Integer> task = new FutureTask<>(()->{log.debug("running");Thread.sleep(1000);return 100;});new Thread(task, "t3").start();Integer result = task.get();log.debug("result = {}", result);}
}
以继承Callable接口的方式实现:
public class MyCallable implements Callable<String> {private int n;public MyCallable(int n) {this.n = n;}@Overridepublic String call() throws Exception {// 描述线程任务,返回线程执行结果int sum = 0;for(int i = 1; i <= n; ++ i){sum += i;}return "线程求出了1-"+ n + "的和是:"+sum;}
}public class ThreadTest3 {public static void main(String[] args) throws Exception {// 前两次重写run方法在不同线程中执行代码无法返回数据// Callable接口,FutureTask类的实现,可以直接返回数据// 创建一个重写了Callable接口的对象Callable<String> call = new MyCallable(100);// Callable的对象封装为FutureTask的对象FutureTask<String> f1 = new FutureTask<>(call);// 作用:// 1.任务对象,实现了Runnable接口// 2. 线程执行饭毕后可以调用get方法获取线程执行完毕后的结果new Thread(f1).start();Callable<String> call2 = new MyCallable(200);FutureTask<String> f2 = new FutureTask<>(call2);new Thread(f2).start();// 获取线程执行完毕后的结果.// get获取的返回结果就是call方法返回的结果// call返回的结果可能是符合返回类型的或者不符合,所有这里有异常,需要抛出System.out.println(f1.get());System.out.println(f2.get());// 如果上面的线程代码没有执行完毕,这里的f1.get方法会暂停,等待上面代码执行完毕才会获取结果}
}
实现原理(继承关系):
- 首先
FutureTask
实现了RunnableFuture
接口RunnableFuture
接口是由Runnable
和Future<V>
接口组成的- 实现了
Runnable
接口的 run 方法 - 实现了
Future<V>
接口的 get 方法
- 在
FutureTask
对run
中的实现:- 获取 callable对象
- 调用 callable对象中的 call 方法
- 等待 call 方法执行完成,获取返回值并赋值给 result
- callable 对象的获取是通过
FutureTask
的构造函数传入的 - 调用实现的 get 方法获取 call方法的返回值 result
- set方法将 result -> outcome
- get方法调用 report方法获取outcome
// 1. FutureTask实现了RunnableFuture接口
public class FutureTask<V> implements RunnableFuture<V>// RunnableFuture接口 继承了 Runnable
public interface RunnableFuture<V> extends Runnable, Future<V> {/*** Sets this Future to the result of its computation* unless it has been cancelled.*/void run();
}// RunnableFuture接口 继承了 Future<V>接口
// get 方法可以获取返回值
public interface Future<V> {// ...V get() throws InterruptedException, ExecutionException;// ...V get(long timeout, TimeUnit unit)throws InterruptedException, ExecutionException, TimeoutException;// ...
}// 2. FutrureTask类中对 run 方法的具体实现:
public void run() {if (state != NEW ||!RUNNER.compareAndSet(this, null, Thread.currentThread()))return;try {Callable<V> c = callable; // 2.1. 获得一个 callable对象if (c != null && state == NEW) {V result;boolean ran;try {result = c.call(); // 2.2. 调用 callable对象中的 call 方法(call方法一般由用户重写)ran = true;} catch (Throwable ex) {result = null;ran = false;setException(ex);}if (ran)set(result); // 2.3. 如果 call 方法执行完毕,则将返回值赋值给result}} finally {// runner must be non-null until state is settled to// prevent concurrent calls to run()runner = null;// state must be re-read after nulling runner to prevent// leaked interruptsint s = state;if (s >= INTERRUPTING)handlePossibleCancellationInterrupt(s);}}
// 3. FutureTask的构造方法,传入了 Callable 接口对象
public FutureTask(Callable<V> callable) {if (callable == null)throw new NullPointerException();this.callable = callable;this.state = NEW; // ensure visibility of callable
}// set 方法将 result 结果赋值给 outcome
protected void set(V v) {if (STATE.compareAndSet(this, NEW, COMPLETING)) {outcome = v;STATE.setRelease(this, NORMAL); // final statefinishCompletion();}
}
// report 方法返回 outcome 结果
private V report(int s) throws ExecutionException {Object x = outcome;if (s == NORMAL)return (V)x;if (s >= CANCELLED)throw new CancellationException();throw new ExecutionException((Throwable)x);
}
// get方法 返回 report中的outcom结果
public V get() throws InterruptedException, ExecutionException {int s = state;if (s <= COMPLETING)s = awaitDone(false, 0L);return report(s);
}