线程的创建

问题1:创建线程有多种方法?

初学Java多线程编程的时候,我们被告知有两种创建多线程的方法:

  • 继承Thread类,重写run方法,如例1;
  • 实现Runnable接口,如例2;

例1:继承Thread类:

class MyThread extends Thread {

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

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

例2:实现Runnable接口:

 public static void main(String[] args)
 {
    Runnable r = () -> {
        System.out.println(Thread.currentThread());
    };
    Thread t = new Thread(r);
    t.start();
 }

然而,仔细观察你可以发现,即使实现了Runnable接口,也还需要把它扔进Thread中。所谓实现Runnable接口,仅仅是定义了线程的工作内容而已。

也许你还听过Callable接口,下面是一种写法:

    static class MCall implements Callable
    {

        @Override
        public String call()
        {
            return "hello";
        }
    }

    public static void main(String[] args)
    {
        Callable callable = new MCall();
        FutureTask task = new FutureTask<>(callable);
        Thread t = new Thread(task);
        t.start();
    }

看,仍然需要创建Thread对象。

不论用什么花招,最终都得老老实实创建Thread或其子类实例。Thread是创建线程的唯一方式

线程池中的线程依然是Thread子类实例。

问题2:new Thread()是创建了一个线程吗?

下面创建了一个Thread实例

    Thread t = new Thread();

到此,我们仅仅得到一个Thread对象,但还没有创建线程。这句话可能让你意外。我们先通过一个例子来看看。

    static class MThread extends Thread
    {
        @Override
        public void run()
        {
            // 打印当前线程名
            System.out.println(Thread.currentThread().getName());
        }
    }

    public static void main(String[] args)
    {
        MThread thread = new MThread();
        thread.run(); // 注意这里调的是run方法
    }

猜猜打印的结果是什么?结果是——
main

还记得在初学java的时候,老师告诉我们要调用start,而不是run,这两者有什么区别?

答案是, start方法内部调用了本地方法start0,这个本地方法才真真切切触发操作系统去创建线程(内核线程),然后,jvm调用run方法运行在新线程上。

如果直接调用run,只是像普通方法一样,并不会创建线程,run方法仍然运行在当前线程中,所以上面运行的结果是main。

小结

通过这篇文章,我们知道了:

  1. 在java中,创建线程必须通过创建Thread或其子类实例并且调用start方法来实现;
  2. start和run的区别。

你可能感兴趣的:(java)