初学Java多线程,后续继续改进
一,Callable
Callable是类似于Runnable的接口,实现Callable接口的类和实现Runnable的类都是可被其他线程执行的任务
Callable和Runnable的区别如下:
1.Callable定义的方法是call,而Runnable定义的方法是run。
2.Callable的call方法可以有返回值,而Runnable的run方法不能有返回值。
3.Callable的call方法可抛出异常,而Runnable的run方法不能抛出异常。
二,Executor
A,几种不同的ExecutorService线程池对象:
1. newCachedThreadPool() 缓存型池子,先查看池中有没有以前建立的线程,如果有,就reuse.如果没有,就建一个新的线程加入池中,自增型
2. newFixedThreadPool(int var0)任意时间点,最多只能有固定数目的活动线程存在,此时如果有新的线程要建立,只能放在另外的队列中等待,直到当前的线程中某个线程终止直接被移出池子
3.SingleThreadExecutor()单例线程,任意时间池中只能有一个线程
4.ScheduledThreadPool()这个池子里的线程可以按schedule依次delay执行,或周期执行
ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(2);
System.out.println("开始时间"+new Date());
threadPool.schedule(new MyExecutor(),2,TimeUnit.SECONDS);
threadPool.schedule(new MyExecutor(),4,TimeUnit.SECONDS);
B,ExecutorService接口常用方法:
1.void shutdown()
这个方法会平滑地关闭ExecutorService,当我们调用这个方法时,ExecutorService停止接受任何新的任务且等待已经提交的任务执行完成(已经提交的任务会分两类:一类是已经在执行的,另一类是还没有开始执行的),当所有已经提交的任务执行完毕后将会关闭ExecutorService
ExecutorService service = Executors.newCachedThreadPool();
service.submit(new MyExecutor());
service.shutdown();
2.boolean isTerminated(int timeout,TimeUnit unit)/boolean isShutdown()
这个方法有两个参数,一个是timeout即超时时间,另一个是unit即时间单位。这个方法会使线程等待timeout时长,当超过timeout时间后,会监测ExecutorService是否已经关闭,若关闭则返回true,否则返回false。一般情况下会和shutdown方法组合使用
ExecutorService executorService= Executors.newCachedThreadPool();
executorService.submit(new MyExecutor());
executorService.submit(new MyExecutor());
executorService.submit(new MyExecutor());
executorService.submit(new MyExecutor());
executorService.shutdown();
System.out.println(executorService.isTerminated()+”-----"+executorService.isShutdown());
3.List<Runnable> shutdownNow()
个方法会强制关闭ExecutorService,它将取消所有运行中的任务和在工作队列中等待的任务,这个方法返回一个List列表,列表中返回的是等待在工作队列中的任务
ExecutorService service = Executors.newFixedThreadPool(3);
service.submit(new MyExecutor());
service.submit(new MyExecutor());
service.submit(new MyExecutor());
service.submit(new MyExecutor());
List<Runnable> runnables = service.shutdownNow();
System.out.println("等待个数:"+runnables.size());
4.boolean awaitTermination(long timeout, TimeUnit unit)
这个方法有两个参数,一个是timeout即超时时间,另一个是unit即时间单位。这个方法会使线程等待timeout时长,当超过timeout时间后,会监测ExecutorService是否已经关闭,若关闭则返回true,否则返回false。一般情况下会和shutdown方法组合使用
ExecutorService service = Executors.newCachedThreadPool();
service.submit(new MyExecutor());
service.submit(new MyExecutor());
service.submit(new MyExecutor());
service.submit(new MyExecutor());
service.shutdown();
try {
while (!service.awaitTermination(1, TimeUnit.SECONDS)) {
System.out.println(“线程池没有关闭”);
}
System.out.println(“线程池已经关闭");
三,Future
Future 表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果。FutureTask类是Future 的一个实现,并实现了Runnable,所以可通过Excutor(线程池) 来执行,也可传递给Thread对象执行,一般FutureTask多用于耗时的计算,主线程可以在完成自己的任务后,再去获取结果
常用方法:
1.boolean cancel(boolean mayInterruptIfRunning) 试图取消对此任务的执行。如果任务已完成、或已取消,或者由于某些其他原因而无法取消,则此尝试将失败。当调用 cancel 时,如果调用成功,而此任务尚未启动,则此任务将永不运行。如果任务已经启动,则 mayInterruptIfRunning 参数确定是否应该以试图停止任务的方式来中断执行此任务的线程。此方法返回后,对 isDone() 的后续调用将始终返回 true。如果此方法返回 true,则对 isCancelled() 的后续调用将始终返回 true
2.boolean isCancelled():如果在任务正常完成前将其取消,则返回 true,如果cancel方法返回 true,则对 isCancelled() 的后续调用将始终返回 true
3.boolean isDone():如果任务已完成,则返回 true。 可能由于正常终止、异常或取消而完成,在所有这些情况中,此方法都将返回 true。
4.V get()throws InterruptedException,ExecutionException:如有必要,等待计算完成,然后获取其结果。
5.V get(long timeout,TimeUnit unit) throws InterruptedException,ExecutionException,TimeoutException:如有必要,最多等待为使计算完成所给定的时间之后,获取其结果(如果结果可用)
class PGPageModelWorker implements Callable<Integer> {
private int shopId;
public PGPageModelWorker(int shopId) {
this.shopId = shopId;
}
@Override
public Integer call() throws Exception {
Random rand = new Random();
int sleep=rand.nextInt(2000) + 500;
// Thread.sleep(sleep);
int s = shopId + 1;
System.out.println(shopId+"执行时间---" + sleep+"毫秒");
return s;
}
}
class FutureTask2Test{
public static void main(String[] args) throws InterruptedException {
final ConcurrentHashMap<String, Integer> modelMap = new ConcurrentHashMap<String, Integer>();
final List<Integer> data=Collections.synchronizedList(new ArrayList<Integer>());
ExecutorService executor = Executors.newCachedThreadPool();
final CountDownLatch countDownLatch = new CountDownLatch(10);//
Long startdate=System.currentTimeMillis();
for (int i = 0; i < 1000; i++) {
final int id = i;
executor.submit(new FutureTask<Integer>(new PGPageModelWorker(id)) {
@Override
protected void done() {
try {
modelMap.put("key" + id, get());
data.add(get());
} catch (Exception e) {
modelMap.put("key" + id, 0);
} finally {
countDownLatch.countDown();
}
}
});
}
System.out.println("----做其他的事------");
System.out.println("------做其他的事----");
System.out.println("-----做其他的事-----");
try {
Thread.sleep(3000);
System.out.println("睡三秒");
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("-----做其他的事-----");
System.out.println("-----做其他的事-----");
System.out.println("-----做其他的事-----");
System.out.println("-----做其他的事-----");
int timeout = 3000;
countDownLatch.await(timeout, TimeUnit.MILLISECONDS);// 超时时间
Long enddate=System.currentTimeMillis();
System.out.println("执行时间:"+(enddate-startdate));
Iterator<String> iterator=modelMap.keySet().iterator();
while (iterator.hasNext()){
String key=iterator.next();
System.out.println(key+"-----"+modelMap.get(key));
}
System.out.println("---list遍历--------");
Long start1=System.currentTimeMillis();
for(Integer d:data){
System.out.println(d);
}
System.out.println("遍历时间:"+(System.currentTimeMillis()-start1));
System.out.println("list.size:"+data.size());
}
}
CountDownLatch
它可以让某些任务完成以后再继续运行下面的内容,每个任务本身执行完毕后让计数器减一,直到计数器清零后,以下的内容才可以继续运行,否则将阻塞等待
CountDownLatch有以下基本方法:
1)await(),阻塞等待,直到计数器清零
2)await(int timeout, TimeUnit unit),使线程阻塞,除非被中断或者超过等待的最大时间
如果达到计数器清零,则await返回true,如果等待超过了最大的等待时间,则返回false
3)countDown(),计数器减一,当计数器清零时,await的线程被唤醒,线程继续执行
4)getCount (),获取当前计数器的大小
public static void main(String[] args) throws Exception{
final CountDownLatch cdOrder=new CountDownLatch(1);
final CountDownLatch cdAnswer=new CountDownLatch(3);
System.out.println("等待运动员入场---------------");
try {
ExecutorService executor= Executors.newCachedThreadPool();;
for (int i = 1; i < 4; i++) {
final int c=i;
executor.submit(new Runnable() {
@Override
public void run() {
try {
System.out.println("运动员"+c+"准备就绪");
cdOrder.await();
System.out.println("运动员"+c+"已经起跑");
Random rand = new Random();
Thread.sleep(rand.nextInt(2000) + 500);
cdAnswer.countDown();
System.out.println("运动员"+c+"已到终点");
System.out.println("还剩"+cdAnswer.getCount()+"个运动员未到");
} catch (Exception e) {
System.out.println("runable problem i="+c);
e.printStackTrace();
}
}
});
}
} catch (Exception e) {
System.out.println("thread problem");
e.printStackTrace();
}
try {
Thread.sleep(1000);
System.out.println("裁判已发布号令-----------------");
cdOrder.countDown();
cdAnswer.await();
System.out.println("裁判宣布结果------------");
} catch (Exception e){
System.out.println("main problem");
e.printStackTrace();
}
}
五,CompletionService
将生产新的异步任务与使用已完成任务的结果分离开来的服务,生产者 submit 执行的任务。使用者 take 已完成的任务,并按照完成这些任务的顺序处理它们的结果
CompletionService有以下基本方法:
Future<V> submit(Callable<V> task);
Future<V> submit(Runnable task, V result);
Future<V> take() throws InterruptedException;
Future<V> poll();
Future<V> poll(long timeout, TimeUnit unit) throws InterruptedException;
class completionService2{
public static void main(String[] args) {
ExecutorService executor = Executors.newCachedThreadPool();
CompletionService<Integer> completionServcie = new ExecutorCompletionService<Integer>(
executor);
completionServcie.submit(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},1);
try {
System.out.println(completionServcie.poll(2000, TimeUnit.MILLISECONDS).get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}