啊,Java线程创建到底有几种方式?面试官会因为你的回答眼前一亮,嗯哼你小子真不错。

52 阅读2分钟

创建线程到底有几种方式?

1. 权威认证

docs.oracle.com/javase/8/do… 兄弟们 官方就是权威

public class MyThread extends Thread{

    public void run() {
        System.out.println("[" + Thread.currentThread().getName() + "线程]: " + "MyThread类中的run方法。");
    }

    public static void main(String[] args) {
        extendClass();

        runnableMethod();
    }

    private static void runnableMethod() {
        System.out.println("[" + Thread.currentThread().getName() + "线程]");//[main线程]
        Thread myThread = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("[" + Thread.currentThread().getName() + "线程]: " + "Runnable对象的run方法");
            }
        });
        myThread.start();//[Thread-0线程]: Runnable对象的run方法
    }

    private static void extendClass() {
        System.out.println(Thread.currentThread().getName());//main
        MyThread myThread = new MyThread();
        myThread.start();//[Thread-0线程]: MyThread类中的run方法。
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

继承Thread类或者传入Runnable 注意观察方法执行的当前线程

2. 构造方法分析

    public Thread() {
        init(null, null, "Thread-" + nextThreadNum(), 0);
    }

    public Thread(Runnable target) {
        init(null, target, "Thread-" + nextThreadNum(), 0);
    }

    Thread(Runnable target, AccessControlContext acc) {
        init(null, target, "Thread-" + nextThreadNum(), 0, acc, false);
    }

    public Thread(ThreadGroup group, Runnable target) {
        init(group, target, "Thread-" + nextThreadNum(), 0);
    }

    public Thread(String name) {
        init(null, null, name, 0);
    }

    public Thread(ThreadGroup group, String name) {
        init(group, null, name, 0);
    }

    public Thread(Runnable target, String name) {
        init(null, target, name, 0);
    }

    public Thread(ThreadGroup group, Runnable target, String name) {
        init(group, target, name, 0);
    }

    public Thread(ThreadGroup group, Runnable target, String name,
                  long stackSize) {
        init(group, target, name, stackSize);
    }

兄弟们 这里有两个注意点

1.线程的命名方式 nextThreadNum() private static int threadInitNumber; private static synchronized int nextThreadNum() { return threadInitNumber++; }

2.Threa类的成员变量 private Runnable target;

3. 为什么一定要调用start方法

思考一个问题 Thread是java的类,java类到底是怎么跟操作系统线程关联上的呢?看看下面的场景

子类不重写run

public class MyThread1 extends Thread{

//    public void run() {
//        System.out.println("[" + Thread.currentThread().getName() + "线程]: " + "MyThread类中的run方法。");
//    }

    public static void main(String[] args) {
        extendClass();
    }


    private static void extendClass() {
        System.out.println(Thread.currentThread().getName());//main
        MyThread1 myThread = new MyThread1();
        myThread.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

  直接调用run

public class MyThread1 extends Thread{

    public void run() {
        System.out.println("[" + Thread.currentThread().getName() + "线程]: " + "MyThread类中的run方法。");
    }

    public static void main(String[] args) {
        extendClass();
    }


    private static void extendClass() {
        System.out.println(Thread.currentThread().getName());//main
        MyThread1 myThread = new MyThread1();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        myThread.run();//[main线程]: MyThread类中的run方法。
    }
    }

现象:没有重写run方法时什么都没发生,只有调用了start方法才会开启新的线程,当直接调用run方法时只是普通的方法调用,执行方法的是当前线程。

原因:这是Thread的run方法

public void run() {
    if (target != null) {
        target.run();
    }
}

当MyThread没有重新run方法时,也没有传入target对象(2可知 这个是Runnable为null)所以什么都没发生。

image.png 而Thread的start()方法最终会调用native的start0,开启操作系统的线程,然后最终虚拟机回调Thread类的run方法,完成闭环。

private native void start0();

 

4. 总结发言

八股文的回答:

  • 继承Thread类
  • 实现Runnable接口
  • 实现Callable和Future
  • 线程池

总结发言:

Thread类是java类,代码层面继承Thread类实现Runnable接口等都是外在表现,如果要创建线程最终是需要调用Thread的start()方法执行native的start0()方法,然后虚拟机会回调Thread的run()方法。