Java多线程实现的三种方式

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

[[224653]]

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.   }   

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

 

  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.   }   

为了启动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.   }   

 

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

 

代码说明:

上述代码中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()方法,会阻塞直到计算完成。 

责任编辑:庞桂玉 来源: Java团长
相关推荐

2022-07-07 00:33:34

Java线程同步

2014-12-31 17:42:47

LBSAndroid地图

2021-11-05 21:33:28

Redis数据高并发

2021-06-24 08:52:19

单点登录代码前端

2022-11-03 08:44:24

代理模式Java设计模式

2009-06-29 18:18:53

Java多线程向线程传递数据

2010-03-12 17:52:35

Python输入方式

2024-07-01 12:42:58

2023-12-04 09:31:13

CSS卡片

2010-07-14 10:30:26

Perl多线程

2022-07-06 07:08:58

CPythonPython返回值

2024-07-08 09:03:31

2022-01-20 08:38:02

Java接口Lambda

2022-01-17 08:19:51

Javascript 接口前端

2024-08-28 11:10:53

2012-07-17 09:16:16

SpringSSH

2010-09-07 16:31:27

CSS

2024-05-27 00:20:00

2009-07-16 16:23:59

Swing线程

2024-08-13 08:25:16

C#外部程序方式
点赞
收藏

51CTO技术栈公众号