`
liugang594
  • 浏览: 977522 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Java线程类三

 
阅读更多

一、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:

  1. 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()方法用于得到返回值,此方法会一直阻塞,直到某个异常发生或者线程调用结束,返回值返回。 
  2. 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线程第3版 java线程第2版第3版合集

    电子书相关:包含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 线程类应用

    JAVA 线程类应用JAVA 线程类应用JAVA 线程类应用JAVA 线程类应用JAVA 线程类应用JAVA 线程类应用JAVA 线程类应用JAVA 线程类应用JAVA 线程类应用

    Java线程详解大全

    Java线程Java线程Java线程Java线程Java线程Java线程Java线程Java线程Java线程Java线程Java线程Java线程Java线程Java线程Java线程

    java多线程编程总结

    Java线程:概念与原理 Java线程:创建与启动 Java线程:线程栈模型与线程的变量 Java线程:线程状态的转换 Java线程:线程的同步与锁 Java线程:线程的交互 Java线程:线程的调度-休眠 Java线程:线程的调度-优先级 ...

    Java线程Java线程Java线程Java线程

    Java线程Java线程Java线程Java线程Java线程Java线程

    java 线程java 线程

    java 线程java 线程java 线程java 线程java 线程java 线程java 线程java 线程java 线程

    Java多线程编程总结

    Java线程:概念与原理 Java线程:创建与启动 Java线程:线程栈模型与线程的变量 Java线程:线程状态的转换 Java线程:线程的同步与锁 Java线程:线程的交互 Java线程:线程的调度-休眠 Java线程:线程的调度-...

    java多线程笔记

    Java线程:概念与原理 2 一、操作系统中线程和进程的概念 2 二、Java中的线程 3 三、Java中关于线程的名词解释 3 四、线程的状态转换和生命周期 4 Java线程:创建与启动 7 Java线程:线程名称的设定及获取 10 Java...

    java 线程 dump 分析工具 2.3.3

    java 线程Dump 分析工具: Java的TDA线程转储分析器是一个用于分析Sun Java VM生成的线程转储和堆信息的小型Swing GUI(目前用1.4测试)。它从提供的日志文件中解析线程转储和类直方图。它提供关于发现的线程转储的...

    Java线程模块Java线程之秒表

    Java线程模块Java线程之秒表新手学习Java线程模块时,利用Java中设置线程的暂停间隔,做的简易秒表

    java线程同步java线程同步

    java线程同步java线程同步java线程同步

    java线程简单的封装类

    用反射实现了对java线程简单的封装,类似c#线程,使用此封装类勿需再次继承Thread类或实现Runnable接口,直接绑定需要使用线程的方法即可,另支持动态传参,如觉着好用请多多支持作者 QQ 359103820 希望能为使用线程...

    java线程 线程学习资料 java线程教程

    java线程 线程 教程 java线程教程 java线程学习资料 本教程有什么内容? 本教程研究了线程的基础知识— 线程是什么、线程为什么有用以及怎么开始编写使用线程的简单 程序。 我们还将研究更复杂的、使用线程的应用...

    Java的线程和Java AppletJava的线程和Java AppletJava的线程和Java Applet

    Java的线程和Java AppletJava的线程和Java AppletJava的线程和Java AppletJava的线程和Java AppletJava的线程和Java Applet

    java线程.pdf

    java线程.pdf java 学习java

    Java线程Java线程

    java 线程 新手java 线程 新手java 线程 新手java 线程 新手

    java线程分析工具TDA

    分析java线程日志的工具,使用jstack把java线程日志dump下来,然后上传到该工具,就可以查看线程阻塞情况等信息。

    Java 模拟线程并发

    Java 模拟线程并发 Java, 模拟线程并发,线程,并发 Java, 模拟线程并发,线程,并发 Java, 模拟线程并发,线程,并发 Java, 模拟线程并发,线程,并发

    Java多线程设计模式上传文件

    Java多线程设计模式上传文件Java多线程设计模式上传文件Java多线程设计模式上传文件Java多线程设计模式上传文件Java多线程设计模式上传文件Java多线程设计模式上传文件Java多线程设计模式上传文件Java多线程设计模式...

Global site tag (gtag.js) - Google Analytics