一、Callable
最早创建线程要么是通过实现Runnable接口,或者是继承Thread类来实现(Thread类本身是Runnable的一个实现类),但是都有一个问题:不能携带返回值。
从Java 5开始,提供了一个Callable接口,可以用来提供带返回值的线程,例如:
class CallableDemo implements Callable<String>{
@Override
public String call() throws Exception {
return "Hello World";
}
}
Callable类似于Runnable,只不过对应的方法名是call(),而不是run(),另外不同与run()方法,call()方法需要指定一个返回值,其中的返回类型由声明实现时的Callable中的GenericType指定。要调用一个Callable不能像Runnable一样简单的使用Thread去启动(看看Thread就知道,它根本就不支持使用Callable)。
有几种方法可以启动一个Callable:
- FutureTask
FutureTask可以接收一个Runnable也可以接收一个Callable,从类继承层次:FutureTask -> RunnableTask -> Runnable 可以看出,FutureTask可能入在一个Thread中,所以可以如下启动用一个调用Callable实现的线程:
FutureTask<String> futureTask = new FutureTask<String>(new CallableDemo());
new Thread(futureTask).start();
String response = futureTask.get();
System.out.println(response);
将Callable放在一个FutureTask中,然后将此FutureTask放在一个Thread中启动;调用FutureTask的get()方法用于得到返回值,此方法会一直阻塞,直到某个异常发生或者线程调用结束,返回值返回。
- Executors
Executors是一个工厂类,提供了一些通用方法来创建各种线程相关对象,例如将一个Runnable转成Callable;创建一个线程池(ThreadPool/ExecutorService);创建一个线程工厂(ThreadFactory)等。其中ExecutorService类可以用来启动一个Callable线程,例如:
CallableDemo callable = new CallableDemo();
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
Future<String> future = singleThreadExecutor.submit(callable);
String response = future.get();
System.out.println(response);
这里用newSingleThreadExecutor()方法是因为只有一个Callable对象要调用。可以换成其他的,例如newFixedThreadPool(int)或newCachedThreadPool()方法,如果还有更多的Callable需要调用。同样的用get()方法得到返回值。
上面用get()方法取返回值,如果线程没结束则会一直阻塞,直到线程取消或结束。如果要想判断当前线程的状态,也可以用isDone()和isCancelled()方法查询当前的状态,然后根据状态再取结果。
不过如果有大量的线程执行,那么一个一个查就不太方便了,这就可以使用下面介绍的ExecutorCompletionService类了。
二、ExecutorCompletionService
上面说了为了得到线程运行结果,需要查询线程的状态,调用future的get()方法来得到结果,如果线程未结束,则get()方法阻塞。如果有大量的线程在运行,则必须一个一个查询这些线程的状态以得到返回结果,针对此,Java刚好提供了一个ExecutorCompletionService类可以用来做这种查询,ExecutorCompletionService类会把所有运行完的线程放到一个有序队列里去,只要调用它的take()方法,就会从中把结果一个一个取出。
首先修改一下上例中的CallableDemo:
class CallableDemo implements Callable<String>{
private int i;
private CountDownLatch latch;
public CallableDemo(int i, CountDownLatch latch) {
this.i = i;
this.latch = latch;
}
@Override
public String call() throws Exception {
latch.await();
System.out.println(i);
return "Hello World "+i;
}
}
增加了一个变量i,用于区别不同的线程;增加了一个变量latch用于在所以线程准备好之前等待。
然后看看创建端:
CountDownLatch latch = new CountDownLatch(10); //设置门槛为20
//创建一个线程数为5的线程池
ExecutorCompletionService<String> completionService = new ExecutorCompletionService<String>(Executors.newFixedThreadPool(5));
//创建20个callable对象,并用completionService去启动它
for(int i = 0;i<10;i++){
completionService.submit(new CallableDemo(i, latch));
latch.countDown();
}
//从completionService中取结果
for(int i = 0;i<10;i++){
Future<String> take = completionService.take(); //如果没有结果,则等待
System.out.println(take.get());
}
在Callable中打印了一下i,是想用来比较一下是不是先完成先被加到完成队列里。下面是某次的运行结果:
4
0
2
1
3
8
7
6
5
Hello World 0
9
Hello World 4
Hello World 2
Hello World 1
Hello World 3
Hello World 8
Hello World 7
Hello World 6
Hello World 5
Hello World 9
可以看到基本上先执行的先被加到队列里(4和0可能基本是同时结束)。
分享到:
相关推荐
java 线程工具类 java 线程工具类java 线程工具类 java 线程工具类java 线程工具类 java 线程工具类java 线程工具类 java 线程工具类java 线程工具类 java 线程工具类java 线程工具类 java 线程工具类java 线程工具...
java 线程相关工具类.java 线程相关工具类.java 线程相关工具类.java 线程相关工具类.java 线程相关工具类.java 线程相关工具类.java 线程相关工具类.java 线程相关工具类.java 线程相关工具类.java 线程相关工具类....
电子书相关:包含4个有关JAVA线程的电子书(几乎涵盖全部有关线程的书籍) OReilly.Java.Threads.3rd.Edition.Sep.2004.eBook-DDU Java Thread Programming (Sams) java线程第二版中英文 java线程第二版中英文 ...
《Java线程(第三版)》是一本深入探讨Java线程技术的专业书籍,旨在帮助开发者理解和掌握Java平台上的多线程编程。Java线程是并发编程的重要组成部分,它允许程序同时执行多个任务,从而充分利用系统资源,提高程序的...
根据提供的信息,我们可以推断出这份文档主要关注的是Java线程的相关内容。下面将围绕“Java线程”这一主题展开详细的介绍与解释。 ### Java线程基础 在Java语言中,线程是程序执行流的基本单元。一个标准的Java...
Java线程类应用是Java编程中的重要组成部分,它关乎到多任务处理和程序并发执行的能力。在Java中,线程是程序执行的最小单位,它允许一个程序中有多个执行流同时进行,使得程序能更高效地利用系统资源,特别是在处理...
Java线程有10个优先级(MIN_PRIORITY, NORM_PRIORITY, MAX_PRIORITY),默认优先级是NORM_PRIORITY。但是,线程优先级并不保证绝对的执行顺序,操作系统调度策略可能影响实际执行顺序。 7. join()方法: 一个线程...
Java线程是并发编程的核心部分,它允许程序在同一时间执行多个独立的任务,从而提高系统效率和响应速度。本文将深入探讨Java线程的概念、生命周期、实现方式以及相关的同步机制。 首先,理解线程的基本概念至关重要...
java 线程Dump 分析工具: Java的TDA线程转储分析器是一个用于分析Sun Java VM生成的线程转储和堆信息的小型Swing GUI(目前用1.4测试)。它从提供的日志文件中解析线程转储和类直方图。它提供关于发现的线程转储的...
《JAVA线程第三版》是Java并发编程领域的一本经典著作,主要针对Java线程的深入理解和实践提供了详尽的指导。这本书详细介绍了如何在Java应用程序中有效地使用多线程,以提高程序的性能和可扩展性。Java线程是Java...
3. **线程优先级**:Java线程有10个优先级,通过`setPriority()`设置,但实际调度仍取决于操作系统。 4. **线程状态**:Java线程有新建、就绪、运行、阻塞和死亡五种状态,可以通过`getState()`获取。 三、线程池...
Java线程是Java编程中的重要概念,特别是在多核处理器和并发处理中不可或缺。Java线程允许程序在同一时间执行多个不同的任务,从而提高了程序的效率和响应性。在燕山大学信息学院计算机系的课程中,李峰教授讲解了...
Java线程是多任务编程的重要概念,它允许程序同时执行多个独立的任务,从而提高系统效率和响应速度。在Java中,线程可以分为用户线程和守护线程,前者是程序运行的基础,而后者是在所有用户线程结束时才终止的后台...
《JAVA线程(第三版)》是一本深入探讨Java多线程编程的权威书籍,针对Java线程的管理和优化提供了详尽的解析。线程在现代计算机编程中扮演着至关重要的角色,尤其是在并发处理和高性能应用中。Java以其强大的线程...
创建Java线程有两种方式:继承`Thread`类并重写`run()`方法,或者实现`Runnable`接口并提供`run()`方法。当线程对象被创建并调用`start()`方法后,线程进入可运行态,由Java的线程调度器决定何时执行`run()`方法。 ...
生成JAVA线程dump的方法在不同的操作系统下是不同的,在Windows环境中,可以敲击Ctrl-Break键,在Unix、Linux和MacOS环境中,可以敲击Ctrl-\键或使用“kill -3 ”命令,Pid是关注的JAVA进程号。 在分析JAVA线程dump...
Java线程是Java编程语言中的一个核心概念,它允许程序同时执行多个任务,极大地提高了程序的效率和响应性。在Java中,线程是通过类`Thread`或实现`Runnable`接口来创建和管理的。Java线程模型是基于操作系统的原生...
Java线程是多任务编程中的核心概念,它允许程序同时执行多个不同的任务,极大地提高了程序的效率和响应性。在Java中,线程是通过Java.lang.Thread类或实现Runnable接口来创建和管理的。这份“java线程文档大全”包含...
Java线程是多任务编程的重要概念,特别是在大型的、复杂的软件系统中,它允许程序同时执行多个不同的任务,提升程序的并发性和效率。本示例"简单的Java线程demo"旨在帮助初学者理解如何在Java中创建和管理线程。 在...
### Java线程培训资料知识点详解 #### 一、Java线程基本概念 1. **如何编写与启动线程** - **方式一:继承Thread类** ```java class MyThread extends Thread { @Override public void run() { // 业务逻辑 ...