Java 线程创建的方法和原理
2023-12-14 12:33:58
创建线程
方法一:Thread 类
创建Thread类的对象,重写其中的 run 方法:
@Slf4j(topic = "c.Test1")
public class d1_Thread {
public static void main(String[] args) {
// 创建 Thread 类的对象
Thread t = new Thread(){
@Override
public void run(){
log.debug("running"); // t1 线程
}
};
t.setName("t1");
t.start();
log.debug("running"); // main线程
}
}
以继承的方式重写 run :
public class MyThread extends Thread{
// 2. 重写Thread类的run方法
@Override
public 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方法
@Override
public 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
方法重写,就等于覆盖了下面的方法。
@Override
public 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;
}
@Override
public 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 interrupts
int 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 state
finishCompletion();
}
}
// 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);
}
文章来源:https://blog.csdn.net/qq_45364953/article/details/134992143
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!