Thread 中的run() 与start() 方法

来源:互联网 发布:生产流程优化 编辑:程序博客网 时间:2024/05/30 04:29

将类声明为 Thread 的子类是创建线程的方式之一,如果我们想要在线程内定义任务那么就要重写Thread 中的run() 方法。start() 方法使我们定义的线程执行,我们已经将线程的任务定义在了run() 方法中为什么run() 方法不是执行线程的方法而是start() 方法呢?当时学线程的时候并没有多考虑这个问题,由于以前有一些误解,现在就写出来供自己与大家参考。

      我定义了一个Thread 的子类ThreadTest ,在该子类中重写了run() 方法,在run() 方法中用于输出当前正在执行的线程引用,为了达到效果我让线程等待了100ms。在创建两个线程对象thread1 与thread2 后直接调用了它们的run() 方法,我们希望得到的结果是thread1 与thread2 共同抢占CPU 以达到交错输出,但是从输出的结果看出在执行的始终是主线程(main)。

public class ThreadTest  extends Thread{    @Override    public void run() {        for(int i = 0; i < 5; i++){            try {                Thread.sleep(100);                //Thread.currentThread() 返回对当前正在执行的线程对象的引用                System.out.println(Thread.currentThread());            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }    public static void main(String[] args) {        TestThread thread1 = new TestThread();        TestThread thread2 = new TestThread();        thread1.run();        thread2.run();    }}

输出:
Thread[main,5,main]
Thread[main,5,main]
Thread[main,5,main]
Thread[main,5,main]
Thread[main,5,main]
Thread[main,5,main]

      下面我们用和上面同样的代码,不再调用ThreadTest 的run() 方法,这次调用start() 方法,看看输出结果会是什么?从下面的结果可以看出这次输出的不再是主线程,而是线程0与线程1 (但是执行的线程也包括主线程)。

public class ThreadTest extends Thread{    @Override    public void run() {        for(int i = 0; i < 3; i++){            try {                Thread.sleep(100);                //Thread.currentThread() 返回对当前正在执行的线程对象的引用                System.out.println(Thread.currentThread());            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }    public static void main(String[] args) {        TestThread thread1 = new TestThread();        TestThread thread2 = new TestThread();        thread1.start();        thread2.start();    }}

输出
Thread[Thread-1,5,main]
Thread[Thread-0,5,main]
Thread[Thread-0,5,main]
Thread[Thread-1,5,main]
Thread[Thread-1,5,main]
Thread[Thread-0,5,main]

      通过执行run() 方法与start() 方法可以知道Thread 并不是通过run() 方法执行线程的而是通过start() 方法执行线程,我们只是把线程的任务定义在了run() 方法中,但是它并不是执行任务的方法。我们知道创建执行线程任务还有一种方式,就是实现Runnable 接口。下面我们就来看一下Runnable 中的run() 方法,为了更好的对比我在run() 方法中定义了和上面一样的任务。通过上面的了解我们知道执行run() 方法并不能让线程执行,所以输出的仍然是主线程的引用。

public class RunnableTest implements Runnable {    @Override    public void run() {        for(int i = 0; i < 3; i++){            try {                Thread.sleep(100);                System.out.println(Thread.currentThread());            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }    public static void main(String[] args) {        RunnableTest runnableTest1 = new RunnableTest();        RunnableTest runnableTest2 = new RunnableTest();        runnableTest1.run();        runnableTest2.run();    }}

输出
Thread[main,5,main]
Thread[main,5,main]
Thread[main,5,main]
Thread[main,5,main]
Thread[main,5,main]
Thread[main,5,main]

      通过看Runnable 接口的源码你就会知道这个接口只定义了一个run() 方法,这也说明着Runnable 并不能创建线程实例,那么怎么执行在其中定义的任务呢?想要创建线程实例还不简单吗,直接new 一个Thread 对象不就好了吗。Thread类 提供了一个 Thread(Runnable target) 构造器,它允许我们传入一个Runnable 子类的实例,下面我们就来这么做。

@FunctionalInterfacepublic interface Runnable {    /**     * When an object implementing interface <code>Runnable</code> is used     * to create a thread, starting the thread causes the object's     * <code>run</code> method to be called in that separately executing     * thread.     * <p>     * The general contract of the method <code>run</code> is that it may     * take any action whatsoever.     *     * @see     java.lang.Thread#run()     */    public abstract void run();}

      重新定义了两个Thread 类实例并将RunnableTest 对象传入Thread 类中的构造器,然后由线程实例thread1 与thread2 执行线程任务,我们看到正如我们所希望的那样打印着执行线程的引用。

public class RunnableTest implements Runnable {    @Override    public void run() {        for(int i = 0; i < 3; i++){            try {                Thread.sleep(100);                System.out.println(Thread.currentThread());            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }    public static void main(String[] args) {        RunnableTest runnableTest1 = new RunnableTest();        RunnableTest runnableTest2 = new RunnableTest();        Thread thread1 = new Thread(runnableTest1);        Thread thread2 = new Thread(runnableTest2);        thread1.start();        thread2.start();    }}

输出
Thread[Thread-1,5,main]
Thread[Thread-0,5,main]
Thread[Thread-1,5,main]
Thread[Thread-0,5,main]
Thread[Thread-1,5,main]
Thread[Thread-0,5,main]

总结:
      Thread 中的run() 方法只是定义了线程的任务但是它不负责执行该任务,如果你调用该方法那么执行的只是主线程,就像某一个对象实例调用它自己的方法一样。
      Thread 中的start() 方法才是执行线程的方法,在执行该方法时,Java 虚拟机会调用该线程的run() 方法,从而达到并发执行的目的。在这里你需要注意的是多次启动一个线程是不安全的,特别是线程执行结束后,不要再重新启动,这点要特别注意。
      在这里也通过实现Runnable 接口来定义线程任务,需要注意的是Runnable 接口的实现并不能创建线程实例,当你想要执行其中定义的任务时,你需要将该子类的实例作为参数传入Thread 中的构造器,通过Thread 类的实例来执行线程任务。

原创粉丝点击