java中建立线程的三种方法以及区别

Java使用Thread类表明线程,全部的线程对象都必须是Thread类或其子类的实例。Java能够用三种方式来建立线程,以下所示:java

1)继承Thread类建立线程编程

2)实现Runnable接口建立线程多线程

3)使用Callable和Future建立线程spa

下面让咱们分别来看看这三种建立线程的方法。线程

 

------------------------继承Thread类建立线程---------------------对象

 

经过继承Thread类来建立并启动多线程的通常步骤以下继承

1】d定义Thread类的子类,并重写该类的run()方法,该方法的方法体就是线程须要完成的任务,run()方法也称为线程执行体。接口

2】建立Thread子类的实例,也就是建立了线程对象资源

3】启动线程,即调用线程的start()方法get

代码实例

public class MyThread extends Thread{//继承Thread类

  public void run(){

  //重写run方法

  }

}

public class Main {

  public static void main(String[] args){

    new MyThread().start();//建立并启动线程

  }

}

------------------------实现Runnable接口建立线程---------------------

经过实现Runnable接口建立并启动线程通常步骤以下:

1】定义Runnable接口的实现类,同样要重写run()方法,这个run()方法和Thread中的run()方法同样是线程的执行体

2】建立Runnable实现类的实例,并用这个实例做为Thread的target来建立Thread对象,这个Thread对象才是真正的线程对象

3】第三部依然是经过调用线程对象的start()方法来启动线程

代码实例:

public class MyThread2 implements Runnable {//实现Runnable接口

  public void run(){

  //重写run方法

  }

}

public class Main {

  public static void main(String[] args){

    //建立并启动线程

    MyThread2 myThread=new MyThread2();

    Thread thread=new Thread(myThread);

    thread().start();

    //或者    new Thread(new MyThread2()).start();

  }

}

------------------------使用Callable和Future建立线程---------------------

和Runnable接口不同,Callable接口提供了一个call()方法做为线程执行体,call()方法比run()方法功能要强大。

》call()方法能够有返回值

》call()方法能够声明抛出异常

Java5提供了Future接口来表明Callable接口里call()方法的返回值,而且为Future接口提供了一个实现类FutureTask,这个实现类既实现了Future接口,还实现了Runnable接口,所以能够做为Thread类的target。在Future接口里定义了几个公共方法来控制它关联的Callable任务。

>boolean cancel(boolean mayInterruptIfRunning):视图取消该Future里面关联的Callable任务

>V get():返回Callable里call()方法的返回值,调用这个方法会致使程序阻塞,必须等到子线程结束后才会获得返回值

>V get(long timeout,TimeUnit unit):返回Callable里call()方法的返回值,最多阻塞timeout时间,通过指定时间没有返回抛出TimeoutException

>boolean isDone():若Callable任务完成,返回True

>boolean isCancelled():若是在Callable任务正常完成前被取消,返回True

介绍了相关的概念以后,建立并启动有返回值的线程的步骤以下:

1】建立Callable接口的实现类,并实现call()方法,而后建立该实现类的实例(从java8开始能够直接使用Lambda表达式建立Callable对象)。

2】使用FutureTask类来包装Callable对象,该FutureTask对象封装了Callable对象的call()方法的返回值

3】使用FutureTask对象做为Thread对象的target建立并启动线程(由于FutureTask实现了Runnable接口)

4】调用FutureTask对象的get()方法来得到子线程执行结束后的返回值

代码实例:

public class Main {

  public static void main(String[] args){

   MyThread3 th=new MyThread3();

   //使用Lambda表达式建立Callable对象

     //使用FutureTask类来包装Callable对象

   FutureTask<Integer> future=new FutureTask<Integer>(

    (Callable<Integer>)()->{

      return 5;

    }

    );

   new Thread(task,"有返回值的线程").start();//实质上仍是以Callable对象来建立并启动线程

    try{

    System.out.println("子线程的返回值:"+future.get());//get()方法会阻塞,直到子线程执行结束才返回

    }catch(Exception e){

    ex.printStackTrace();

   }

  }

}

--------------------------------------三种建立线程方法对比--------------------------------------

实现Runnable和实现Callable接口的方式基本相同,不过是后者执行call()方法有返回值,后者线程执行体run()方法无返回值,所以能够把这两种方式归为一种这种方式与继承Thread类的方法之间的差异以下:

一、线程只是实现Runnable或实现Callable接口,还能够继承其余类。

二、这种方式下,多个线程能够共享一个target对象,很是适合多线程处理同一份资源的情形。

三、可是编程稍微复杂,若是须要访问当前线程,必须调用Thread.currentThread()方法。

四、继承Thread类的线程类不能再继承其余父类(Java单继承决定)。

注:通常推荐采用实现接口的方式来建立多线程

相关文章
相关标签/搜索