您的位置:首页 > 编程语言 > Java开发

多线程并发库高级应用 之 java5中的线程并发库--线程池、Callable&Future

2012-12-11 19:56 1051 查看

笔记摘要:

这里首先介绍了java5中的并发的小工具包:automatic,然后介绍了线程池的概念,对使用java5的方式创建不同形式的线程进行了演示,

之后介绍了两个 对象:Callable和Future,用于获取线程执行后的结果,对于线程锁技术则在另外一篇文章中介绍。

Java5中的线程并发库都在java.util.concurrent包及子包中

一、java.util.concurrent.atomic包:

类的小工具包,支持在单个变量上解除锁的线程安全编程

1、如果同一个变量要被多个线程访问,则可以使用该包中的类:

AtomicBooleanAtomicIntegerAtomicLongAtomicReference

2、AtomicIntegerArray:操作数组里面的某个整数

3、同样该包中提供了可以用于反射操作的类:

AtomicReferenceFieldUpdater、
AtomicIntegerFieldUpdaterAtomicLongFieldUpdater

它们可以提供对关联字段类型的访问。

二、线程池:

在线程池的编程模式下,任务是提交给整个线程池,而不是直接交给某个线程,线程池在拿到任务后,它就在内部找有无空闲的线程,

再把任务交给内部某个空闲的线程,这就是封装。

记住:任务是提交给整个线程池,一个线程同时只能执行一个任务,但可以同时向一个线程池提交多个任务。

示例:

创建固定大小的线程池、创建缓存线程池 、 用线程池创建定时器

创建单一线程池(始终保证线程池中会有一个线程在。当某线程死去,会找继任者)

注意:

定时器中总是相对时间,我们要想指定具体时间的方法:比如明天早上10点钟执行,则可以使用明天早上10点的时间减去

当前的时间,得到时间间隔

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class ThreadPoolTest {
public static void main(String[] args){

//创建固定大小的线程池,这里只能完成3个任务
//ExecutorService threadPool = Executors.newFixedThreadPool(3);

//创建缓存线程池,根据任务来自动创建线程的数量,可以完成创建的所有任务
//ExecutorService threadPool = Executors.newCachedThreadPool();

//创建单一线程池(始终保持线程池中有一个线程存活。当唯一线程死去,会创建新的继任者、
ExecutorService threadPool = Executors.newSingleThreadExecutor();

for(int i=1;i<=10;i++){
  //内部类不能访问外部类的局部变量,所以i要定义为final,又由于i++.
  //所以在循环内部定义一个变量接收i
final int task = i;
threadPool.execute(new Runnable() {

@Override
public void run() {
for(int j=1;j<=10;j++){
System.out.println(Thread.currentThread().getName()
+" is looping of "+ j+"  for task of " +task);
}

}
});
}
//验证10个任务都提交给了线程池
System.out.println("all of 10 tasks have committed! ");
//threadPool.shutdown();		//等任务完成后,杀死线程、
//threadPool.shutdownNow();		//立即停止线程

//用线程池启动定时器

Executors.newScheduledThreadPool(3).schedule(
new Runnable() {  //任务
@Override
public void run() {
System.out.println("bombing!");
}
},
5,	//5秒以后执行
TimeUnit.SECONDS);	//单位

//在某个时间执行一次后,再指定后续的执行间隔时间
Executors.newScheduledThreadPool(3).scheduleAtFixedRate(new Runnable(){

@Override
public void run() {
System.out.println("bombing!");
}

}, 10,   //第一次在10秒时爆炸
3,			//以后每隔3秒爆炸一次。
TimeUnit.SECONDS);

}
}


三、Callable & Future:用于获取线程执行完的结果

1、Callable 接口类似于Runnable,两者都是为那些其实例可能被另一个线程执行的类设计的。但是 Runnable 不会返回结果,

并且无法抛出经过检查的异常,而Callable返回结果并且可能抛出异常的任务。

2、Future 接口表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并获取计算的结果。计算完成后只能

使用 get 方法来获取结果,如有必要,计算完成前可以阻塞此方法。

3、Future取得的结果类型和Callable返回的结果类型必须一致,这是通过泛型来实现的。

Callable要采用ExecutorService的submit方法提交,返回的future对象可以取消任务、

4、CompletionService用于提交一组Callable任务,其take方法返回已完成的一个Callable任务对应的Future对象。

示例:

这里数据的获取好比同时种了号几块地的麦子,然后等待收割,秋收时,哪块先熟,先收割哪块。

import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class CallableAndFuture {
public static void main(String[] args){

  //创建一个单独的线程
  ExecutorService threadPool = Executors.newSingleThreadExecutor();
  //future泛型与Callable的类型一致
  Future<String> future = threadPool.submit(new Callable<String>(){

@Override
public String call() throws Exception {
Thread.sleep(3000);
return "hello";
}

});
System.out.println("等待結果……");

//在指定时timeout内等待,未等到抛出TimeoutException
//System.out.println("拿到结果:" + future.get(long timeout,TimeUnit unit));

try {
System.out.println("拿到结果:" + future.get());	//获取线程执行后的结果

} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

//CompletionService用于提交一组Callable任务,
//其take方法返回已完成的一个Callable任务对应的Future对象。
ExecutorService threadPool2 = Executors.newFixedThreadPool(10);
CompletionService<Integer> completionService = new ExecutorCompletionService<Integer>(threadPool2);

              //创建10任务
for(int i=1;i<=10;i++){
final int seq = i;

              //将任务提交给线程池
completionService.submit(new Callable<Integer>(){
@Override
public Integer call() throws Exception {
Thread.sleep(new Random().nextInt(5000));
return seq;
}
});
}
//获取结果,哪个结果先返回就先获得
for(int i=0;i<10;i++){
try {
System.out.println(completionService.take().get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: