`
androidssh
  • 浏览: 115243 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

Java线程学习笔记之Executor

    博客分类:
  • java
阅读更多
Java线程学习笔记之Executor

   并发编程的一种编程方式是把任务拆分为一系列的小任务,即Runnable,然后在提交给一个Executor执行,Executor在执行时使用内部的线程池完成操作。由此,任务提交者不需要再创建管理线程,使用更方便,也减少了开销。有两种任务:Runnable和Callable,Callable是需要返回值的任务。Task Submitter把任务提交给Executor执行,他们之间需要一种通讯手段,这种手段的具体实现,通常叫做Future。Future通常包括get ,cancel,get(timeout) 等等。Future也用于异步变同步的场景。
例子1
import java.util.concurrent.*;
import java.util.*;

class TaskWithResult implements Callable<String> {
private int id;

public TaskWithResult(int id) {
this.id = id;
}

public String call() {
return "result of TaskWithResult " + id;
}
}

public class CallableDemo {
public static void main(String[] args) {
ExecutorService exec = Executors.newCachedThreadPool();
ArrayList<Future<String>> results = new ArrayList<Future<String>>();
for (int i = 0; i < 10; i++)
results.add(exec.submit(new TaskWithResult(i)));
for (Future<String> fs : results)
try {
// get() blocks until completion:
System.out.println(fs.get());
} catch (InterruptedException e) {
System.out.println(e);
return;
} catch (ExecutionException e) {
System.out.println(e);
} finally {
exec.shutdown();
}
}
}
通过call方法从任务中产生返回值,submit方法会产生一个future对象,当任务完成时可以通过idDone方法来判断任务是否完成,通过get方法获得任务完成后的返回值。

运行结果:
result of TaskWithResult 0
result of TaskWithResult 1
result of TaskWithResult 2
result of TaskWithResult 3
result of TaskWithResult 4
result of TaskWithResult 5
result of TaskWithResult 6
result of TaskWithResult 7
result of TaskWithResult 8
result of TaskWithResult 9

Executors
   包含Executor、ExecutorService、ScheduledExecutorService、ThreadFactory 和 Callable类的工厂和实用方法。支持以下各种方法:

创建并返回设置有常用配置字符串的 ExecutorService 的方法。
创建并返回设置有常用配置字符串的 ScheduledExecutorService 的方法。
创建并返回“包装的”ExecutorService 方法,它通过使特定于实现的方法不可访问来禁用重新配置。
创建并返回 ThreadFactory 的方法,它可将新创建的线程设置为已知的状态。
创建并返回非闭包形式的 Callable 的方法,这样可将其用于需要 Callable 的执行方法中。
具体的方法说明如下:

callable(PrivilegedAction action)
返回 Callable 对象,调用它时可运行给定特权的操作并返回其结果。
callable(PrivilegedExceptionAction action)
返回 Callable 对象,调用它时可运行给定特权的异常操作并返回其结果。
callable(Runnable task)
返回 Callable 对象,调用它时可运行给定的任务并返回 null。
callable(Runnable task, T result)
返回 Callable 对象,调用它时可运行给定的任务并返回给定的结果。
defaultThreadFactory()
返回用于创建新线程的默认线程工厂。
newCachedThreadPool()
创建一个可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用它们。
newCachedThreadPool(ThreadFactory threadFactory)
创建一个可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用它们,并在需要时使用提供的 ThreadFactory 创建新线程
newFixedThreadPool(int nThreads)
创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程。
newFixedThreadPool(int nThreads, ThreadFactory threadFactory)
创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程,在需要时使用提供的 ThreadFactory 创建新线程
newScheduledThreadPool(int corePoolSize)
创建一个线程池,它可安排在给定延迟后运行命令或者定期地执行。
newScheduledThreadPool(int corePoolSize, ThreadFactory threadFactory)
创建一个线程池,它可安排在给定延迟后运行命令或者定期地执行。
newSingleThreadExecutor()
创建一个使用单个 worker 线程的 Executor,以无界队列方式来运行该线程。
newSingleThreadExecutor(ThreadFactory threadFactory)
创建一个使用单个 worker 线程的 Executor,以无界队列方式来运行该线程,并在需要时使用提供的 ThreadFactory 创建新线程。
newSingleThreadScheduledExecutor()
创建一个单线程执行程序,它可安排在给定延迟后运行命令或者定期地执行。
newSingleThreadScheduledExecutor(ThreadFactory threadFactory)
创建一个单线程执行程序,它可安排在给定延迟后运行命令或者定期地执行。
privilegedCallable(Callable callable)
返回 Callable 对象,调用它时可在当前的访问控制上下文中执行给定的 callable 对象。
privilegedCallableUsingCurrentClassLoader(Callable callable)
返回 Callable 对象,调用它时可在当前的访问控制上下文中,使用当前上下文类加载器作为上下文类加载器来执行给定的 callable 对象。
privilegedThreadFactory()
返回用于创建新线程的线程工厂,这些新线程与当前线程具有相同的权限。
unconfigurableExecutorService(ExecutorService executor)
返回一个将所有已定义的 ExecutorService 方法委托给指定执行程序的对象,但是使用强制转换可能无法访问其他方法。
unconfigurableScheduledExecutorService(ScheduledExecutorService executor)
返回一个将所有已定义的 ExecutorService 方法委托给指定执行程序的对象,但是使用强制转换可能无法访问其他方法。

ScheduledExecutorServices
   尽管ExecutorService接口非常有用,但某些任务仍需要以计划方式执行,比如以确定的时间间隔或在特定时间执行给定的任务。这就是 ScheduledExecutorService的应用范围,它扩展了ExecutorService。

例如创建一个每隔 5 秒跳一次的 “心跳” 命令,使用ScheduledExecutorService可以轻松实现:

public static void main(String[] args) {
ScheduledExecutorService ses = Executors.newScheduledThreadPool(1);
Runnable pinger = new Runnable() {
public void run() {
System.out.println("PING!");
}
};

ses.scheduleAtFixedRate(pinger, 5, 5, TimeUnit.SECONDS);
}

   不用过于担心线程,不用过于担心用户希望取消心跳时会发生什么,也不用明确地将线程标记为前台或后台;只需将所有的计划细节留给ScheduledExecutorService。如果用户希望取消心跳,scheduleAtFixedRate调用将返回一个ScheduledFuture实例,它不仅封装了结果(如果有),还拥有一个cancel方法来关闭计划的操作。

下面是一个完整的示例,并行计算数组的和。

利用CompletionService,生产者submit()执行的任务。使用者take()已完成的任务,并按照完成这些任务的顺序处理它们的结果 。也就是调用CompletionService的take方法是,会返回按完成顺序放回任务的结果,CompletionService内部维护了一个阻塞队列BlockingQueue,如果没有任务完成,take()方法也会阻塞。

完整代码如下:

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;

public class ConcurrentCalculator {
private ExecutorService exec;
private CompletionService<Long> completionService;
private int cpuCoreNumber;

class SumCalculator implements Callable<Long> {
private int[] numbers;
private int start;
private int end;

public SumCalculator(final int[] numbers, int start, int end) {
this.numbers = numbers;
this.start = start;
this.end = end;
}

public Long call() throws Exception {
Long sum = 0l;
for (int i = start; i < end; i++) {
sum += numbers[i];
}
return sum;
}
}

public ConcurrentCalculator() {
cpuCoreNumber = Runtime.getRuntime().availableProcessors();
exec = Executors.newFixedThreadPool(cpuCoreNumber);
completionService = new ExecutorCompletionService<Long>(exec);
}

public Long sum(final int[] numbers) {
for (int i = 0; i < cpuCoreNumber; i++) {
int increment = numbers.length / cpuCoreNumber + 1;
int start = increment * i;
int end = increment * i + increment;
if (end > numbers.length)
end = numbers.length;
SumCalculator subCalc = new SumCalculator(numbers, start, end);
if (!exec.isShutdown()) {
completionService.submit(subCalc);
}
}

return getResult();
}

public Long getResult() {
Long result = 0l;
for (int i = 0; i < cpuCoreNumber; i++) {
try {
Long subSum = completionService.take().get();
result += subSum;
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}

return result;
}

public void close() {
exec.shutdown();
}

public static void main(String[] args) {
int[] numbers = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 34 };
ConcurrentCalculator calc = new ConcurrentCalculator();
Long sum = calc.sum(numbers);
System.out.println(sum);
calc.close();
}
}

分享到:
评论

相关推荐

    java线程学习笔记

    Java线程学习笔记涉及了Java多线程编程的多个关键知识点,本篇知识点整理将详细解释每个概念及其在Java中的实现方式。 基本知识部分包含了Java线程编程的基础内容,它们是并发编程的基石。 任务Runnable是一个接口...

    java多线程学习笔记

    - Java线程有10个优先级,从MIN_PRIORITY(1)到MAX_PRIORITY(10),默认优先级是NORM_PRIORITY(5)。 - 优先级高的线程并不保证一定先执行,线程调度还受到操作系统的限制。 6. **线程中断** - **interrupt()...

    java多线程笔记全手打

    本笔记全面涵盖了多线程的学习,包括基础理论和实践代码,旨在帮助开发者深入理解并掌握Java多线程技术。 一、线程基础知识 线程是操作系统分配CPU时间的基本单位,一个进程中可以包含多个线程。Java通过`Thread`类...

    多线程-狂神说Java学习笔记

    本学习笔记将深入探讨Java多线程的相关知识,包括其原理、实现方式、同步机制以及常见问题。 ### 一、多线程的基本概念 多线程是指在一个程序中存在两个或更多的执行线程,这些线程共享同一内存空间,但各自拥有...

    java多线程代码笔记

    Java多线程是Java编程中的重要概念,它允许程序同时执行多个任务,从而提高系统效率和资源利用率。在Java中,实现多线程有两种主要方式:通过实现`Runnable`接口和继承`Thread`类。 首先,让我们从创建线程开始。当...

    Java JDK 7学习笔记(国内第一本Java 7,前期版本累计销量5万册)

     《Java JDK 7学习笔记》将IDE操作纳为教学内容之一,使读者能与实践结合,提供的视频教学能更清楚地帮助读者掌握操作步骤。 内容简介 书籍 计算机书籍  《java jdk 7学习笔记》是作者多年来教学实践经验的总结...

    多线程学习笔记.docx

    Java提供了interrupt()方法来中断线程,但需要注意的是,中断并不会立即终止线程,而是设置线程的中断标志。线程可以通过检查中断标志来决定是否结束执行,例如在while循环中检查isInterrupted()或在捕获...

    JAVA课程学习笔记.doc

    本篇学习笔记将深入解析Java线程池的框架、结构、原理以及相关源码,帮助读者全面理解线程池的工作机制。 1. 线程池模块结构 线程池框架分为多层结构,其中包括核心实现类、辅助类和接口等组件。例如,`sun.nio.ch....

    JAVA并发编程实践-线程执行-学习笔记

    占式线程调度是Java和大多数现代操作系统采用的线程调度策略。在这种模式下,操作系统决定何时以及哪个线程将获得CPU的执行时间。线程的执行不是由线程自身控制,而是由操作系统通过时间片轮转或者优先级调度等方式...

    马士兵多线程笔记.zip

    7. **线程池**:Java的Executor框架引入了线程池的概念,通过预先创建一组可重用的线程,可以有效地管理和控制线程数量,避免频繁创建和销毁线程带来的开销。 8. **并发集合**:Java的并发包(java.util.concurrent...

    线程四笔记,对于正在学习Java的朋友可以参考一下

    【线程基础与Java线程】 Java线程是并发编程的核心,它允许程序同时执行多个任务,提升系统效率。在Java中,有两种主要的创建线程的方式:实现Runnable接口和继承Thread类。 1. **实现Runnable接口**: - 创建一...

    学习笔记 java\CoreJava笔记\CoreJava_day18.doc

    第十八天的学习笔记主要涵盖了`synchronized`关键字的使用及其在处理共享数据时的重要性,同时也提到了新线程类的创建方式。 `synchronized`关键字用于实现线程同步,它可以作用于方法或代码块,以控制对特定对象的...

    java学习笔记JDK6课件和课本代码

    本资源"java学习笔记JDK6课件和课本代码"是一个针对初学者和有一定基础的开发者的学习资料集合,它涵盖了JDK6版本的相关内容。 JDK6是Java历史上的一个重要版本,发布于2006年,引入了许多新特性,包括增强的Swing...

    Java线程系列操作.zip

    在Java编程中,线程是程序执行的基本单元,它允许应用程序同时执行多个任务。...通过对这些示例代码的学习,我们可以深入理解Java线程的创建、管理、同步以及并发编程中的最佳实践,从而提升我们的多线程编程能力。

    JUC多线程学习个人笔记

    1. **线程池**:JUC通过Executor框架实现了线程池,允许开发者根据需求创建和管理线程。线程池可以减少线程创建和销毁的开销,提高系统的响应速度和资源利用率。线程池的核心组件包括ExecutorService、...

    java学习笔记.7z

    这份"java学习笔记.7z"压缩包中包含了作者在学习Java过程中整理的基础知识,旨在为初学者提供指导。以下是笔记中可能涵盖的重要知识点的详细解释: 1. **概述** - Java的历史:由Sun Microsystems开发,后被Oracle...

    java学习笔记

    Java学习笔记是一个全面涵盖Java编程语言的学习资源,旨在帮助初学者和有经验的开发者深入理解并熟练掌握Java技术。这份文档可能包含了从基础语法到高级特性的详细讲解,旨在为读者提供一个系统的Java学习路径。 在...

    java并发库学习笔记

    `ExecutorService`是`Executor`接口的一个扩展,它添加了生命周期管理的方法,包括启动、关闭和终止线程池。`ExecutorService`允许我们提交任务(Runnable或Callable)来执行,并且可以控制线程池的行为,如设置线程...

    良葛格Java JDK 5.0学习笔记.rar

    《良葛格Java JDK 5.0学习笔记》是一份详尽的教程资源,旨在帮助开发者深入理解并掌握Java开发工具包(Java Development Kit)的第5个主要版本——JDK 5.0。这份笔记涵盖了JDK 5.0中的核心特性、改进和新功能,是...

Global site tag (gtag.js) - Google Analytics