Java多线程实现方式主要有三种:继承Thread类、实现Runnable接口、使用ExecutorService、Callable、Future实现有返回结果的多线程。其中前两种方式线程执行完后都没有返回值,只有最后一种是带返回值的。

1、继承Thread类实现多线程
继承Thread类的方法尽管被我列为一种多线程实现方式,但Thread本质上也是实现了Runnable接口的一个实例,它代表一个线程的实例,并且,启动线程的唯一方法就是通过Thread类的start()实例方法。start()方法是一个native方法,它将启动一个新线程,并执行run()方法。这种方式实现多线程很简单,通过自己的类直接extend Thread,并复写run()方法,就可以启动新线程并执行自己定义的run()方法。例如:

  1. public class MyThread extends Thread {
  2.   public void run() {
  3.    System.out.println("MyThread.run()");
  4.   }
  5. }

在合适的地方启动线程如下:

  1. MyThread myThread1 = new MyThread();
  2. MyThread myThread2 = new MyThread();
  3. myThread1.start();
  4. myThread2.start();

2、实现Runnable接口方式实现多线程
如果自己的类已经extends另一个类,就无法直接extends Thread,此时,必须实现一个Runnable接口,如下:

  1. public class MyThread extends OtherClass implements Runnable {
  2.   public void run() {
  3.    System.out.println("MyThread.run()");
  4.   }
  5. }

为了启动MyThread,需要首先实例化一个Thread,并传入自己的MyThread实例:

  1. MyThread myThread = new MyThread();
  2. Thread thread = new Thread(myThread);
  3. thread.start();

事实上,当传入一个Runnable target参数给Thread后,Thread的run()方法就会调用target.run(),参考JDK源代码:

  1. public void run() {
  2.   if (target != null) {
  3.    target.run();
  4.   }
  5. }

3、使用ExecutorService、Callable、Future实现有返回结果的多线程
ExecutorService、Callable、Future这个对象实际上都是属于Executor框架中的功能类。想要详细了解Executor框架的可以访问http://www.javaeye.com/topic/366591 ,这里面对该框架做了很详细的解释。返回结果的线程是在JDK1.5中引入的新特征,确实很实用,有了这种特征我就不需要再为了得到返回值而大费周折了,而且即便实现了也可能漏洞百出。
可返回值的任务必须实现Callable接口,类似的,无返回值的任务必须Runnable接口。执行Callable任务后,可以获取一个Future的对象,在该对象上调用get就可以获取到Callable任务返回的Object了,再结合线程池接口ExecutorService就可以实现传说中有返回结果的多线程了。下面提供了一个完整的有返回结果的多线程测试例子,在JDK1.5下验证过没问题可以直接使用。代码如下:

  1. import java.util.concurrent.*;
  2. import java.util.Date;
  3. import java.util.List;
  4. import java.util.ArrayList;
  5.  
  6. /**
  7. * 有返回值的线程
  8. */
  9. @SuppressWarnings("unchecked")
  10. public class Test {
  11. public static void main(String[] args) throws ExecutionException,
  12. InterruptedException {
  13. System.out.println("----程序开始运行----");
  14. Date date1 = new Date();
  15.  
  16. int taskSize = ;
  17. // 创建一个线程池
  18. ExecutorService pool = Executors.newFixedThreadPool(taskSize);
  19. // 创建多个有返回值的任务
  20. List<Future> list = new ArrayList<Future>();
  21. for (int i = ; i < taskSize; i++) {
  22. Callable c = new MyCallable(i + " ");
  23. // 执行任务并获取Future对象
  24. Future f = pool.submit(c);
  25. // System.out.println(">>>" + f.get().toString());
  26. list.add(f);
  27. }
  28. // 关闭线程池
  29. pool.shutdown();
  30.  
  31. // 获取所有并发任务的运行结果
  32. for (Future f : list) {
  33. // 从Future对象上获取任务的返回值,并输出到控制台
  34. System.out.println(">>>" + f.get().toString());
  35. }
  36.  
  37. Date date2 = new Date();
  38. System.out.println("----程序结束运行----,程序运行时间【"
  39. + (date2.getTime() - date1.getTime()) + "毫秒】");
  40. }
  41. }
  42.  
  43. class MyCallable implements Callable<Object> {
  44. private String taskNum;
  45.  
  46. MyCallable(String taskNum) {
  47. this.taskNum = taskNum;
  48. }
  49.  
  50. public Object call() throws Exception {
  51. System.out.println(">>>" + taskNum + "任务启动");
  52. Date dateTmp1 = new Date();
  53. Thread.sleep();
  54. Date dateTmp2 = new Date();
  55. long time = dateTmp2.getTime() - dateTmp1.getTime();
  56. System.out.println(">>>" + taskNum + "任务终止");
  57. return taskNum + "任务返回运行结果,当前任务时间【" + time + "毫秒】";
  58. }
  59. }

代码说明:
上述代码中Executors类,提供了一系列工厂方法用于创先线程池,返回的线程池都实现了ExecutorService接口。
public static ExecutorService newFixedThreadPool(int nThreads) 
创建固定数目线程的线程池。
public static ExecutorService newCachedThreadPool() 
创建一个可缓存的线程池,调用execute 将重用以前构造的线程(如果线程可用)。如果现有线程没有可用的,则创建一个新线程并添加到池中。终止并从缓存中移除那些已有 60 秒钟未被使用的线程。
public static ExecutorService newSingleThreadExecutor() 
创建一个单线程化的Executor。
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) 
创建一个支持定时及周期性的任务执行的线程池,多数情况下可用来替代Timer类。

ExecutoreService提供了submit()方法,传递一个Callable,或Runnable,返回Future。如果Executor后台线程池还没有完成Callable的计算,这调用返回Future对象的get()方法,会阻塞直到计算完成。

转载于:http://www.cnblogs.com/yezhenhan/archive/2012/01/09/2317636.html

Java创建多线程的三种方法的更多相关文章

  1. Java 创建多线程的三种方法

    1. 继承Thread类2. 实现Runnable接口3. 匿名类的方式 注: 启动线程是start()方法,run()并不能启动一个新的线程

  2. java创建线程的三种方法

    这里不会贴代码,只是将创建线程的三种方法做个笼统的介绍,再根据源码添加上自己的分析. 通过三种方法可以创建java线程: 1.继承Thread类. 2.实现Runnable接口. 3.实现Callab ...

  3. java创建多线程的三种方式

    /***************************继承Thread类创建多线程************************/ public class FirstThread extends ...

  4. Java创建线程的三种方法比较

    一般有三种方法,Thread,Runnable,Callable. Runnable和Callable的区别 (1)Callable规定的方法是call(),Runnable规定的方法是run(). ...

  5. Java创建数组的三种方法

    ■ 第一种: int[] arr=new int[6]; arr[0] = 1; arr[1] = 2 arr[2] = 3; arr[3] = 4; arr[4] = 5; arr[5] = 6; ...

  6. java 创建线程的三种方法Callable,Runnable,Thread比较及用法

    转自:http://www.chinaitlab.com/Java/line/942440.html 编写多线程程序是为了实现多任务的并发执行,从而能够更好地与用户交互.一般有三种方法,Thread, ...

  7. 《Java多线程面试题》系列-创建线程的三种方法及其区别

    1. 创建线程的三种方法及其区别 1.1 继承Thread类 首先,定义Thread类的子类并重写run()方法: package com.zwwhnly.springbootaction.javab ...

  8. (转)Java结束线程的三种方法

    背景:面试过程中问到结束线程的方法和线程池shutdown shutdownnow区别以及底层的实现,当时答的并不好. Java结束线程的三种方法 线程属于一次性消耗品,在执行完run()方法之后线程 ...

  9. java创建线程的四种方法

    第一种:  通过继承Thread类创建线程 第二种: 通过实现Runnable接口创建线程 这两种早已烂记于心,这里就不作过多的介绍, 主要介绍其源码 Thread类 implements Runna ...

随机推荐

  1. JavaMail入门:创建纯文本、HTML格式的邮件

    转自:http://haolloyin.blog.51cto.com/1177454/353849/ 在 http://java.sun.com/products/javamail/ 下载了 Java ...

  2. Lua学习之类型与值

    Lua是一种动态语言,在语言中没有类型定义的语法. 在lua中有8中基本的类型: 1.nil(空) 2.boolean 3.number(数字) 4.string(字符串) 5.userdata(自定 ...

  3. 关于TagHelper的那些事情——自定义TagHelper(TagHelper的Attributes)

    接上 Attributes 在最新的VS2015RC版,开始支持了TagHelper的智能提示,主要体现在在写TagHelper有Attributes的提示,正确的Tag和Attribute会变成粗体 ...

  4. Synopsys EDA工具在LinuxMint 18(Ubuntu 16.04.2)安装注意事项

    Synopsys家的工具官方对Linux发行版支持为RHEL 5/6/7及SUSE 12/13,对于2014版本的工具(DC.ICC.PT.VCS.HSPICE等).其实,在Debian系及衍生版本上 ...

  5. PHP之is_a()函数执行代码之总结

    今天看到云舒在群里贴的漏洞公告,原始的文章在 http://www.byte.nl/blog/2011/09/23/security-bug-in-is_a-function-in-php-5-3-7 ...

  6. RenderMonkey 练习 第三天 【OpenGL renderToTexture】

    渲染到纹理: 1. 新建一个OpenGL 空effect; 2. 添加渲染目标纹理, Add Texture-> Add Render Texture 3. 添加一个渲染pass 4. 将pas ...

  7. TensorFlow------TFRecords的分析与存储实例

    TensorFlow------TFRecords的分析与存储实例: import os import tensorflow as tf # 定义cifar的数据等命令行参数 FLAGS = tf.a ...

  8. Add Two Numbers(from leetcode python 链表)

    给定两个非空链表来表示两个非负整数.位数按照逆序方式存储,它们的每个节点只存储单个数字.将两数相加返回一个新的链表. 你可以假设除了数字 0 之外,这两个数字都不会以零开头. 示例: 输入:(2 -& ...

  9. rsa实现js前台加密java后台解密

    前段时间写了一个rsa前台加密到后台用java解密,下面共享下实现思路: 准备工作:第三方包是必须的 bcprov-jdk15on-148.jar commons-codec-1.7.jar comm ...

  10. Spark Streaming updateStateByKey和mapWithState源码解密

    本篇从二个方面进行源码分析: 一.updateStateByKey解密 二.mapWithState解密 通过对Spark研究角度来研究jvm.分布式.图计算.架构设计.软件工程思想,可以学到很多东西 ...