【多线程】实现:Thread、Runable、Callable

本文详细介绍了四种多线程实现方式:Thread类、Runnable接口、Callable接口和线程池。通过具体代码示例,对比分析了每种方式的特点及适用场景。特别深入解析了FutureTask类与Callable接口如何配合实现多线程并获取返回值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

多线程的实现方式:

多线程的实现方式,目前有4中: Thread、Runnable、Callable、线程池【本文不介绍】

  1. Thread类 :通过继承Thread类,并重写其中的Run()方法,调用Thread.start() 方法启动线程
  2. Runnable接口:实现Runnable接口,并且完成Run()方法,仍需借用Thread.start()方法启动线程
  3. Callable接口: 通过实现接口,重写call()方法【有返回值】,通过 FutureTask装饰,最终也是需要Thread.start()方法启动线程

代码示例:

  1. 继承Thread :
public class ThreadTest extends Thread{

    public static void main(String[] args) {
        ThreadTest threadTest = new ThreadTest();
        threadTest.start();
    }

    @Override
    public void run() {
        System.out.println("I am Thread! ");
    }
}

运行结果:

I am Thread! 
  1. 实现Runnable 接口 :
public class RunnableTest implements Runnable {

    public static void main(String[] args) {
        RunnableTest runnableTest = new RunnableTest();
        new Thread(runnableTest).start();
    }

    @Override
    public void run() {
        System.out.println("I am Runnable");
    }
}

运行结果:

I am Runnable
  1. Callable接口实现多线程需要借助 FutureTask 类:
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class CallableTest implements Callable {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        CallableTest callableTest = new CallableTest();
        FutureTask<String> task = new FutureTask<String>(callableTest);
        new Thread(task).start();
        System.out.println(task.get());

    }

    @Override
    public Object call() throws Exception {
        return "I am CallableTest !";
    }
}

运行结果:

I am CallableTest!

源码解析:

关于Thread类 和 Runnable接口,我们可以看到:
  1. Runnable 中 :
public interface Runnable {
   
    // 定义了Run()方法,执行入口,业务逻辑均在此方法中实现
    public abstract void run();
    
  1. 在Thread中:
public  class Thread implements Runnable {

	// Runnable的实现类, 上面的实例代码 runnableTest 对象
	private Runnable target;

  // 线程启动方法
   public synchronized void start() {
       
       // 状态校验  0:NEW 新建状态
        if (threadStatus != 0)
            throw new IllegalThreadStateException();
            
         // 添加进线程组 -main 方法中, 后续调用
        group.add(this);

        boolean started = false;
        try {
           //调用native方法执行线程run方法
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    // 启动失败,从线程组中移除当前前程
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
                /* do nothing. If start0 threw a Throwable then
                  it will be passed up the call stack */
            }
        }
    }

    // 原生的方法
    private native void start0();

   // 当多线程的实现方式实现Runnable 接口时,通过 thread.run() 方法调用 runnableTest.run()方法
    public void run() {
        if (target != null) {
            target.run();
        }
    }
    
   // 省略代码

}
  1. 我们可以看到不管是Thread 还是 Runnable 线程的真正实现都是有Thread.start() 方法启用的。
    再调用 原生start0() , 回调到 run() 方法中【Runnable 通过thread.run() 方法调用 target.run(),实现我们的业务逻辑】
  2. Thread 和 Runnable 的区别就在于,Java 是单继承 和多实现,使用Thread 类 难免会对我们的业务扩展产生影响。
  3. 面试中还有一个常问的问题:如果一个线程多次Start 后的结果 , 答案就在于 if (threadStatus != 0) throw new IllegalThreadStateException() 这两代码,每次启动时都会判断 当前 thread 的运行状态,上次的start 会使得 threadStatus != 0 继而抛出异常。
关于FutureTask类 和 Callable接口实现的多线程:
  1. Callable 接口
public interface Callable<V> {
   
   // 计算结果,如果无法执行,则引发异常
    V call() throws Exception;
}
  1. FutureTask 继承关系:
    在这里插入图片描述
    FutureTask 部分源码:
public class FutureTask<V> implements RunnableFuture<V> {


    // 实现 Runnable run() 方法
    public void run() {
        //  判断当前线程的状态
        if (state != NEW || !UNSAFE.compareAndSwapObject(this, runnerOffset, null, Thread.currentThread()))
            return;
        try {
            Callable<V> c = callable;
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {
                    // 执行 Call 方法,并获得返回结果
                    result = c.call();
                    ran = true;
                } catch (Throwable ex) {
                    // call 方法抛出异常
                    result = null;
                    ran = false;
                    setException(ex);
                }
                // 执行成功将 返回结果放到 outcome 中,在通过get()获得
                if (ran)
                    set(result);
            }
        } finally {
            runner = null;
            int s = state;
            if (s >= INTERRUPTING)
                handlePossibleCancellationInterrupt(s);
        }
    }

    // 等待线程结束,获得线程的返回值 outcome
    public V get() throws InterruptedException, ExecutionException {
        int s = state;
        if (s <= COMPLETING)
            // 等待线程执行结束,或者执行异常
            s = awaitDone(false, 0L);
        return report(s);
    }

    // 等待线程执行结束,或者执行异常 ,并返回线程的状态
    private int awaitDone(boolean timed, long nanos)
            throws InterruptedException {
        final long deadline = timed ? System.nanoTime() + nanos : 0L;
        WaitNode q = null;
        boolean queued = false;
        // 自旋等待线程执行结束
        for (;;) {
            // 线程被中断
            if (Thread.interrupted()) {
                removeWaiter(q);
                throw new InterruptedException();
            }

            int s = state;
            // 执行结束返回
            if (s > COMPLETING) {
                if (q != null)
                    q.thread = null;
                return s;
            }
            else if (s == COMPLETING) // cannot time out yet
                Thread.yield();
            else if (q == null)
                q = new WaitNode();
            else if (!queued)
                queued = UNSAFE.compareAndSwapObject(this, waitersOffset,
                        q.next = waiters, q);
            else if (timed) {
                nanos = deadline - System.nanoTime();
                if (nanos <= 0L) {
                    removeWaiter(q);
                    return state;
                }
                LockSupport.parkNanos(this, nanos);
            }
            else
                LockSupport.park(this);
        }
    }
}
  1. 结合 Callable 和 FutureTask 源码不难发现, FutureTask 本身是实现了Runnable 接口,已经帮我们实现了多线程功能,我们定义的 CallableTest 作为一个 变量 赋值 FutureTask#callable 参数中,
  2. 在执行 Thread#start() 方法中,会调用 FutureTask#run() 方法,再到我们的 callable.call() 方法,进入到我们的业务,并把返回值赋值给 outCome。
  3. 当我们通过 task.get() 回去返回值时,通过等待 线程执行结束,获得 call() 的返回值并返回。
  4. 总而言之, FutureTask 是个已经写好了的线程对象,我仅需吧 Callable交给他执行,即可
以上仅为博主的简单认识,多多评论交流。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值