Java并发之神修炼之路---创建多线程的三种方式

来源:互联网 发布:hold the door知乎 编辑:程序博客网 时间:2024/04/30 07:58

清晨,阳光明媚,秋早早地就来到了“训练室”,刚进门,只见大师飞一般地敲着键盘,空格键如拍子一样打着节奏,宛如一首美妙的音乐。秋来到了大师身旁,拿出电脑开了机,大师瞅了一眼秋,说,“上次对多线程有了一个大概的认识吧”,秋点了点头,“那今天就让你开开眼吧,见识一下启动多线程的三剑客”。
启动多线程一般有三种方式,我们常用的就两种
第一种: 继承Thread类
只见大师键锋一转,飞速的写了几行代码

package com.blog.james;public class TestExtendThread extends Thread{    @Override    public void run(){        System.out.println("我抢到了CPU,我是通过继承Thread类创建的线程");    }    public static void main(String[] args) {        System.out.println("我是主线程,接下来我要新创建一个线程,和我一块抢占CPU资源");        TestExtendThread thread = new TestExtendThread();        thread.start();    }}

运行结果如下:
我是主线程,接下来我要新创建一个线程,和我一块抢占CPU资源
我抢到了CPU,我是通过继承Thread类创建的线程

“看到了吧,这就是一种创建的方式,首先,当你点击Eclipse中的Run as Java Application 的时候,你的程序先启动一个main线程”,然后系统在运行main线程的过程中,它遇到了TestExtendThread thread = new TestExtendThread();这一条语句,因为TestExtendThread这个类继承Thead类,所以电脑(电脑中的JVM应用程序)会新创建一个线程,当执行到`thread.start();这句语句的时候,这个线程就会进入Ready(准备)状态,这时候它会等待CPU空闲了,然后去抢占CPU的使用权,抢到之后,就会去执行该线程的run方法“大师说道,然后转头又去写第二种方法了

第二种:实现Runnable接口

package com.blog.james;public class TestRunnableThread implements Runnable{    @Override    public void run() {        System.out.println("我是实现Runnable接口的线程");    }    public static void main(String[] args) {        System.out.println("主线程开始运行");        Runnable runnable = new TestRunnableThread();        Thread thread = new Thread(runnable);        thread.start();    }}

运行结果如下:
主线程开始运行
我是实现Runnable接口的线程

只要给Thread类的构造方法里面仍一个实现Runnable的实现类,然后new一下Thread,那么就会创建一个线程,执行Runnable实现类中的run方法。

“两种方法看起来挺简单的吧,你说说这两种方法的异同吧?”大师说道,秋对比了两种方法,说道,这两种方法都用到了Thread类,但是第一种方法是直接继承Thread类,然后new 这个继承Thread类的子类就可以使用了,而,第二种方法要我们先去实现一个 Runnable 接口,然后再去把 Runnable 接口的实现类的实例传给 Thread 类的构造函数,这样才可以使用。 “嗯嗯,掌握的不错嘛,那我就再告诉你一些知识吧,其实Thread类也是实现了 Runnable 接口的,看一下源码吧

`publicclass Thread implements Runnable {        ... // 省略若干  private Runnable target;                                                          public Thread(Runnable target) {          init(null, target, "Thread-" + nextThreadNum(), 0);      }    private void init(ThreadGroup g, Runnable target, String name,                     long stackSize) {          init(g, target, name, stackSize, null);     }                                      private void init(ThreadGroup g, Runnable target, String name,                     long stackSize, AccessControlContext acc) {                     ... // 省略若干                     this.target = target;                     ... // 省略若干 }   @Override       public void run() {     if (target != null) {          target.run();     }  }}`”
public interface Runnable {    public abstract void run();}

从源码中你可以看到,当你使用继承Thread类的时候,其实你已经实现了Runnable接口,而你用继承Thread类写的run方法就覆盖了父类的run方法(也就是源码中的run()方法),到时候调用的就是你写的run方法,

但是当你通过实现Runnable 接口实现线程的时候,你是通过 Thread 类的一个构造函数传进来一个 参数,这个参数就是实现Runnable的一个实现类,你的这个实现类就实现了Runnable 的run方法,当程序跑起来的时候,是会先去执行Thread类中的run方法的,如果target不为空,那么,这个时候就调用 target.run(),而target就是你传进来的实现Runnable的实现类,那么这时候的调用的 run() 就是你自己定义的 run

这个有点绕,自己再仔细的想想吧,还有一个创建线程的方式就是:通过Callable和Future创建线程,这个暂时不给你说,等以后你的功力达到了再传授给你吧。秋点了点头。就这样,秋带着兴奋和懵懂走出了房间,回去看大师写的代码去了。

原创粉丝点击