Java 创建线程的三种方式

在java中,目前创建线程的一共有三种形式:

    1. 使用Thread类创建线程

    2. 使用Runnable接口创建线程

    3. 使用Callable接口和Future类创建线程

 

使用Thread类创建线程:

   使用Thread类创建线程是三种方法里面最简单的,因为直接继承了Thread类,当继承Thread类创建了一个对象,这个对象便是线程对象

class FristThread extends Thread{     //继承Thread类
    private int i;
    public FristThread(int i){
        this.i = i;
    }
    public void run(){               //重写Run方法,并编写线程执行体
        for(;i<100;i++){
            System.out.println(this.getName() +" "+ i);
        }
    }
}
public class Threads{
    public static void main(String[] args){
        for(int i=0;i<100;i++){
            System.out.println(Thread.currentThread().getName()+" "+i);
            if(i == 20){
                new FristThread(i).start();  //创建线程并调用
                new FristThread(i).start();
            }
        }
    }
}

使用Runnable接口创建线程:

 使用Runnable接口创建线程,比使用Thread类创建线程要复杂一些。步骤如下:

  1. 定义Runnable接口实现类,并重写run方法,该方法内放入线程执行体

  2. 创建Runnable实现类的实例,并以此实例作为Thread的target来创建Thread对象

 说简单点,继承Runnable接口实现类只是编写线程执行程序(线程执行体),并将线程执行程序赋值到Thread对象的run方法,真正线程对象依然是Thread类(或是继承Thread实现类)的实例,

 

class SecondeThread implements Runnable{     //Runnable接口实现类

    private int i;
    @Override
    public void run() {
        // TODO Auto-generated method stub
        for(;i<100;i++){
            System.out.println(Thread.currentThread() +" "+ i);
        }
    }
}
public class Threads{
    public static void main(String[] args){
        for(int i=0;i<100;i++){
            System.out.println(Thread.currentThread().getName()+" "+i);
            if(i == 40){
                SecondeThread st = new SecondeThread();  //创建实现类的实例
                new Thread(st).start();                  //创建线程,调用实现类的实例,并运行
                new Thread(st).start();                  
            }
        }
    }
} 

使用Callable接口和Future接口创建线程:

 使用Callable接口和Future类创建线程是三种方法中创建线程最复杂,步骤如下:

  1.创建Callable接口的实现类,并重写call()方法,该call()方法作为线程执行体,可以有返回值,可以声明抛出异常,Java 8开始可以直接使用Lambda表达式创建Callable对象

  2.使用FutureTask类来包装Callable对象,FutureTask类继承了Future接口以及Runnable接口,Future接口用于获取Callable接口call()方法的返回值

  3.使用FutureTask对象作为Thread的target创建并启动线程,一个FutureTask对象只能创建一个线程

  4.使用FutureTask对象的get()方法获取子线程执行结束后的返回值

class ThirdThread implements Callable{

    private int i;
    @Override
    public Object call() throws Exception {
        // TODO Auto-generated method stub
        for(;i<100;i++){
            System.out.println(Thread.currentThread() +" "+ i);
        }
        return i;
    }
    
}
public class Threads{
    public static void main(String[] args){
        for(int i=0;i<100;i++){
            System.out.println(Thread.currentThread().getName()+" "+i);
            if(i == 60){
                ThirdThread tt = new ThirdThread();
                FutureTask<Integer> task = new FutureTask<Integer>(tt);
//                FutureTask<Integer> task1 = new FutureTask<Integer>(tt);
                new Thread(task,"有返回值的线程1").start();
                new Thread(task,"有返回值的线程2").start();
                try {
                    System.out.println("子线程返回值:"+task.get());
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (ExecutionException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }
}

 

总结:

为什么会有三种创建线程的方式,原因如下:

    1.类只能继承一个父类,但可以继承多个接口。如果一个类要继承一个父类,那么就不能继承Thread类来创建线程,因此有了实现继承接口来创建线程,这就是1与2和3的区别。

    2.方法2 和方法3都是继承接口的形式来创建线程,区别在于,方法二是重写了Run方法,没有返回值,而方法三是重写了call方法,是有返回值的,只是返回值需要线程执行体执行完后才返回。

    鉴于上面分析:若要创建线程,最好采用继承Runnale或者Callable接口形式会更好一些。

PS  完整代码:

/**
 * 线程
 * */
class FristThread extends Thread{
    private int i;
    public FristThread(int i){
        this.i = i;
    }
    public void run(){
        for(;i<100;i++){
            System.out.println(this.getName() +" "+ i);
        }
    }
}
class SecondeThread implements Runnable{

    private int i;
    @Override
    public void run() {
        // TODO Auto-generated method stub
        for(;i<100;i++){
            System.out.println(Thread.currentThread() +" "+ i);
        }
    }
}

class ThirdThread implements Callable{

    private int i;
    @Override
    public Object call() throws Exception {
        // TODO Auto-generated method stub
        for(;i<100;i++){
            System.out.println(Thread.currentThread() +" "+ i);
        }
        return i;
    }
    
}
public class Threads{
    public static void main(String[] args){
        for(int i=0;i<100;i++){
            System.out.println(Thread.currentThread().getName()+" "+i);
            if(i == 20){
                new FristThread(i).start();
                new FristThread(i).start();
            }else if(i == 40){
                SecondeThread st = new SecondeThread();
                new Thread(st).start();
                new Thread(st).start();
            }else if(i == 60){
                ThirdThread tt = new ThirdThread();
                FutureTask<Integer> task = new FutureTask<Integer>(tt);
//                FutureTask<Integer> task1 = new FutureTask<Integer>(tt);
                new Thread(task,"有返回值的线程1").start();
                new Thread(task,"有返回值的线程2").start();
                try {
                    System.out.println("子线程返回值:"+task.get());
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (ExecutionException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }
}
View Code

 

posted @ 2019-08-20 11:30  HJLのH  阅读(379)  评论(0编辑  收藏  举报