Java 创建线程的三种方式详解

Java如何创建线程

首先关于“创建线程的三种方式”这种说辞,笔者认为容易产生歧义并为初学者带来不必要的误解,不如说是自定义线程的三种方式更为合理(但后文依然使用创建线程的说法),因为创建线程这一具体的操作,最终都是在本地方法start0()中完成的。

无论采用继承Thread类、实现Runnable接口还是实现Callable接口创建线程,最终创建时都要调用Thread的start()方法,start()方法中真正创建线程的是本地方法start0()。

public synchronized void start() {
        if (threadStatus != 0)
            throw new IllegalThreadStateException();
            
        group.add(this);

        boolean started = false;
        try {
        	// 实际创建线程
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
            }
        }
    }
	// 本地方法 CPP实现线程创建
    private native void start0();

start0映射到了C++的JVM_ENTRY函数中

JVM_ENTRY(void, JVM_StartThread(JNIEnv* env, jobject jthread))
  JVMWrapper("JVM_StartThread");
  JavaThread *native_thread = NULL;
  
  bool throw_illegal_thread_state = false;
  {
    MutexLocker mu(Threads_lock); // 加锁
    
    if (java_lang_Thread::thread(JNIHandles::resolve_non_null(jthread)) != NULL) {
      throw_illegal_thread_state = true;
    } else {
 	  // 计算线程大小
      jlong size =
            java_lang_Thread::stackSize(JNIHandles::resolve_non_null(jthread));

      size_t sz = size > 0 ? (size_t) size : 0;
      // 创建Java线程
      native_thread = new JavaThread(&thread_entry, sz);

      if (native_thread->osthread() != NULL) {
        native_thread->prepare(jthread);
      }
    }
  }

Thread创建线程

自定义类继承Thread方法,并且重写run方法,需要创建线程时调用Thread的start()方法即可。

如果直接调用run()方法,包括使用类实现Runnable直接调用run()方法,或使用类实现Callable直接调用call()方法,本质都是当前线程(示例场景中为main线程)调用方法,并不会真正的创建线程。

public class Test {

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

    static class ThreadTest extends Thread{
        @Override
        public void run(){
            System.out.println(this.toString());

        }
    }
}

测试输出如下:

Thread[Thread-0,5,main]
Process finished with exit code 0

Runnable创建线程

自定义类实现Runnable接口,实现run方法,需要创建线程时,需要创建新的Thread对象并将Runnable子类实例作为参数传入,调用Thread的start方法创建。

public class Test {

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

    static class RunnableTest implements Runnable{

        @Override
        public void run() {
            System.out.println(Thread.currentThread());
        }
    }

}

测试输出如下:

Thread[Thread-0,5,main]
Process finished with exit code 0

Callable创建线程

查询文档可以发现Thread的构造方法不支持Callable子类作为参数传入,因此需要利用FutureTask作为媒介(FutureTask是Runnable的实现类),FutureTask对象可以用于获取Callable子类的执行返回值,还可以判断线程是否执行完毕。

自定义类实现Callable接口,并实现call()方法,与Runnable不同,call()方法支持异常抛出以及返回值,需要创建线程时,先将Callable子类实例作为参数创建FutureTask对象,再以FutureTask实例作为参数创建Thread对象,调用Thread的start()方法。

public class Test {

    public static void main(String[] args) {
        CallableTest callableTest = new CallableTest();
        FutureTask futureTask = new FutureTask(callableTest);
        new Thread(futureTask).start();
        try {
        	// 利用FutureTask判断线程是否执行完毕并获取返回值
            while(!futureTask.isDone())
            System.out.println(futureTask.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }

    static class CallableTest implements Callable<Integer>{

        @Override
        public Integer call() throws Exception {
            System.out.println(Thread.currentThread());
            return 10;
        }
    }
}

测试输出如下:

Thread[Thread-0,5,main]
10
Process finished with exit code 0

区别

  • 直接继承Thread类创建编码简单,但无法再继承其他类,其余两种相反。
  • 使用Thread创建线程时,可以直接使用this关键字获取当前线程,Runnable和Callable需要调用Thread.currentThread()方法。
  • 只有使用Callale创建线程,可以获取到线程的返回值,且支持异常抛出。
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

7rulyL1ar

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值