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);
        }
    }
}

注意实现:

  1. 启动子线程要调用start方法,而不是run方法,否则还是只有main线程
  2. 子线程任务要放在主线程之前,如果主线程在子线程之前,主线程任务就一定在子线程任务前

缺点:

  • 线程类已经继承了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 的返回值

实现:

  1. 创建 FutureTask 的对象,传入 Callable参数,泛型选择返回值类型,重写其中的call方法
  2. FutureTask 对象传入 Thread 对象
  3. 调用 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方法会暂停,等待上面代码执行完毕才会获取结果
    }
}

实现原理(继承关系):

  1. 首先 FutureTask 实现了 RunnableFuture 接口
    • RunnableFuture 接口是由 RunnableFuture<V> 接口组成的
    • 实现了 Runnable 接口的 run 方法
    • 实现了 Future<V> 接口的 get 方法
  2. FutureTaskrun 中的实现:
    1. 获取 callable对象
    2. 调用 callable对象中的 call 方法
    3. 等待 call 方法执行完成,获取返回值并赋值给 result
  3. callable 对象的获取是通过 FutureTask的构造函数传入的
  4. 调用实现的 get 方法获取 call方法的返回值 result
    1. set方法将 result -> outcome
    2. 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
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。