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

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

多线程的实现方式:

多线程的实现方式,目前有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交给他执行,即可
以上仅为博主的简单认识,多多评论交流。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值