• 创建线程的三种方式对比


     Java中使用Thread代表线程类,所有的线程类都必须是Thread类或者其子类的实例。每个线程的作用就是完成一定的任务,即执行一段程序流。Java中使用线程执行体来表示这段程序流。

    Java中线程的实现方式有如下三种:

    1.继承Thread类

    public class Thread extends Object implements Runnable

    定义Thread类的子类,并重写Thread类的run()方法,创建子类对象(即线程对象),调用线程对象的start()方法来启动该线程。eg:

    1.  
      public class ThreadDemo extends Thread {
    2.  
       
    3.  
      private int i;
    4.  
      public void run(){
    5.  
      for(; i<100 ;i++){
    6.  
      System.out.println(getName() +" "+ i);
    7.  
      }
    8.  
      }
    9.  
      public static void main(String[] args) {
    10.  
      for(int i = 0 ;i<100; i++){
    11.  
      //currentThread是Thread类的静态方法,该方法返回当前正在执行的线程对象
    12.  
      //getName()返回当前线程对象的名字
    13.  
      System.out.println(Thread.currentThread().getName()+" "+i);
    14.  
      if(i==20){
    15.  
      //启动两个线程,但是实际上有三个线程,即main主线程
    16.  
      //用户启动的多个线程的名字依次为Thread-0、Thread-1、、、、
    17.  
      new ThreadDemo().start();
    18.  
      new ThreadDemo().start();
    19.  
      }
    20.  
      }
    21.  
       
    22.  
      }
    23.  
       
    24.  
      }

    注意:该例中第一次出现的变量i是实例变量,而每次创建线程对象时候,Thread-0和Thread-1两个线程对象不能共享实例变量i。即使用继承Thread方法创建线程对象时,多个线程之间无法共享线程类的实例变量。

    2.实现Runnable接口

    public interface Runnable

    定义Runnable接口的实现类,并重写该接口的run()方法,该run()方法同样是该线程的执行体。创建该Runnable实现类的实例,并将此实例作为Thread的target(即构造函数中的参数)来创建Thread对象(该Thread对象才是真正的线程对象,只是该Thread对象负责执行其target的run()方法)。最后调用线程对象的start()方法来启动该线程。eg:

    1.  
      public class ThreadDemo implements Runnable {
    2.  
       
    3.  
      private int i;
    4.  
      <strong>public void run</strong>(){
    5.  
      for(; i<100 ;i++){
    6.  
      //当线程类实现Runnable接口时,只能通过Thread.currentThread()方法获得当前线程
    7.  
      System.out.println(Thread.currentThread().getName() +" "+ i);
    8.  
      }
    9.  
      }
    10.  
      public static void main(String[] args) {
    11.  
      for(int i = 0 ;i<100; i++){
    12.  
      System.out.println(Thread.currentThread().getName()+" "+i);
    13.  
      if(i==20){
    14.  
      ThreadDemo td = new ThreadDemo();
    15.  
      //创建两个Thread对象,并且均把Runnable接口实例对象作为target
    16.  
      new Thread(td).start();
    17.  
      new Thread(td).start();
    18.  
      }
    19.  
      }
    20.  
       
    21.  
      }
    22.  
       
    23.  
      }


    从运行的结果可以看到实例变量i的输出是连续的。也就是使用Runnable接口创建的多个线程是可以共享线程类的实例变量,这是因为多个线程可以共享同一个target,所以多个线程可以共享同一个线程类(target类)的实例属性。

    3.使用Callable和Future

    public interface Future<V>  

    public interface Callable<V>

    public interfaceRunnableFuture<V> extends RunnableFuture<V>

    public class FutureTask<V>extends Object implementsRunnableFuture<V>

          Java5之后,提供了Callable接口,看起来像是Runnable接口的增强版:该接口提供call()方法来作为线程执行体。与run()相比,call()方法更强大,该方法可以有返回值,并且可以声明抛出异常。

         但是Callable不是Runnable接口的子类,不能作为Thread的target。而且call()方法返回的值如何调用呢?

         Java5给出了Future接口,来获得call()方法的返回值。并提供了FutureTask实现类,该类实现了Runnale接口和Future接口---可以作为Thread类的target。

         创建并启动有返回值的线程的步骤如下:

         创建Callable接口的实现类,并实现call()方法,该方法有返回值;创建Callable实现类的实例,使用FutureTask来包装Callable对象,并且也封装了call()方法的返回值;使用FutureTask作为Thread类的target创建并启动线程;调用FutureTask对象的get()方法返回子线程执行结束后的返回值。

    1.  
      import java.util.concurrent.Callable;
    2.  
      import java.util.concurrent.FutureTask;
    3.  
       
    4.  
      public class CallableDemo implements Callable<Integer>{
    5.  
      //实现call()方法,作为线程执行体
    6.  
      public Integer call(){
    7.  
      int i = 5;
    8.  
      for( ; i<100 ; i++){
    9.  
      System.out.println(Thread.currentThread().getName() + "的循环变量i的值:" +i);
    10.  
      }
    11.  
      //call()方法可以有返回值
    12.  
      return i;
    13.  
      }
    14.  
      public static void main(String[] args) {
    15.  
      //创建Callable对象
    16.  
      CallableDemo cd = new CallableDemo();
    17.  
      //使用FutureTask来包装Callable对象
    18.  
      FutureTask<Integer> task = new FutureTask<Integer>(cd);
    19.  
      for(int i=0 ; i<100 ; i++){
    20.  
      System.out.println(Thread.currentThread().getName() + "的循环变量i的值:" +i);
    21.  
      if(i==20){
    22.  
      //实质还是以Callable对象来创建并启动线程
    23.  
      new Thread(task,"有返回值的线程").start();
    24.  
      }
    25.  
      }
    26.  
      try{
    27.  
      System.out.println("子线程的返回值" + task.get());
    28.  
       
    29.  
      }catch(Exception e){
    30.  
      e.printStackTrace();
    31.  
      }
    32.  
       
    33.  
      }
    34.  
       
    35.  
      }


     FutureTask是Future接口的实现类。Future接口提供了一些方法来控制他关联的Callable任务。

    boolean cancel(boolean mayInterruptIfRunning)
    Attempts to cancel execution of this task. //视图取消该Future关联的Callable任务
    V get()
    Waits if necessary for the computation to complete, and then retrieves its result. 
    //返回call()方法的返回值,调用该方法将导致程序阻塞,必须等到子线程结束后才会有返回值
    V get(long timeout, TimeUnit unit)
    Waits if necessary for at most the given time for the computation to complete, and then retrieves its result, if available.
    //设置阻塞时间
    boolean isCancelled()
    Returns true if this task was cancelled before it completed normally.
    boolean isDone()
    Returns true if this task completed.

    Callable有泛型限制,Callable接口里的泛型形参类型与Call()方法返回值类型相同。

    4.创建线程的三种方式对比

    实现Runnable和Callable接口的方法基本相同,只不过Callable接口定义的方法可以有返回值,而且可以声明抛出异常而已。

    因此采用实现Runnable和Callable接口方式创建多线程——

    优势:

    1.线程类只是实现了接口类,还可以继承其他类

    2.在这种方式下,多个线程可以共享同一个target对象,所以非常适合多个相同线程类处理同一份资源的情况。

    劣势:

    编程稍稍复杂,如果要访问当前线程必须使用Thread.currentThread()方法

    而继承Thread方式则与之相反,因为已经继承了Thread类,不能再继承其他类。编写简单,如果要访问当前线程,直接使用this即可获得当前线程。

    故一般建议采用实现Runnable、Callable接口的方式实现多线程。

    --------------------- 本文来自 亮仔亮仔我爱你哟 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/fffllllll/article/details/52269568?utm_source=copy 

  • 相关阅读:
    solr源码解读(转)
    solr安装配置
    HTML转义字符
    JAVA:在0-99间产生100个不重复的随机数
    JS中的$符号
    使用Emacs敲出UML,PlantUML快速指南
    operator 安装
    package handler
    shell 条件判断if
    libvirtError: internal error: No more available PCI slots
  • 原文地址:https://www.cnblogs.com/yunleijava/p/11545524.html
Copyright © 2020-2023  润新知