newFixedThreadPool与Callable结合用法

本文介绍了一个使用Java实现的多线程求和示例,通过ExecutorService管理线程池,将数组切分为多个部分并行计算,最后汇总结果。文章展示了如何利用线程池提高程序的执行效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


package com.sohu.test;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;

/**
* @author qiaowang
* @date 2013-12-26 上午10:39:01
*/
public class TestThreadDemo {

private ExecutorService exec;
private int cpuNum;
private List<Future<Long>> tasks = new ArrayList<Future<Long>>();

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 TestThreadDemo() {
cpuNum = Runtime.getRuntime().availableProcessors();
exec = Executors.newFixedThreadPool(cpuNum);
}

public Long sum(final int[] numbers) {
// 根据CPU核心个数拆分任务,创建FutureTask并提交到Executor
System.out.println(cpuNum);
for (int i = 0; i < cpuNum; i++) {
int increment = numbers.length / cpuNum + 1;
int start = increment * i;
int end = increment * i + increment;
if (end > numbers.length)
end = numbers.length;
SumCalculator subCalc = new SumCalculator(numbers, start, end);
FutureTask<Long> task = new FutureTask<Long>(subCalc);
tasks.add(task);
if (!exec.isShutdown()) {
exec.submit(task);
}
}
return getResult();
}

public Long getResult() {
Long result = 0l;
for(Future<Long> task : tasks){
try {
Long subSum = task.get();
result +=subSum;
} catch (Exception 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 ,12};
TestThreadDemo calc = new TestThreadDemo();
Long sum = calc.sum(numbers);
System.out.println(sum);
calc.close();
}
}



参见
http://www.iteye.com/topic/366591

Executors类,提供了一系列工厂方法用于创先线程池,返回的线程池都实现了ExecutorService接口。
public static ExecutorService newFixedThreadPool(int nThreads)
创建固定数目线程的线程池。
public static ExecutorService newCachedThreadPool()
创建一个可缓存的线程池,调用execute 将重用以前构造的线程(如果线程可用)。如果现有线程没有可用的,则创建一个新线程并添加到池中。终止并从缓存中移除那些已有 60 秒钟未被使用的线程。
public static ExecutorService newSingleThreadExecutor()
创建一个单线程化的Executor。
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
创建一个支持定时及周期性的任务执行的线程池,多数情况下可用来替代Timer类。
<think>我们使用Callable接口创建线程,通常需要结合FutureTask或线程池(ExecutorService)来执行。Callable接口允许线程返回结果,并且可以抛出异常,这比Runnable更灵活。 关键点:多个线程可以共享同一个Callable实例(target对象),这样它们就可以共同操作该实例内部的共享资源。但需要注意的是,由于多个线程并发访问同一资源,我们必须确保操作是线程安全的。 下面通过一个代码示例来展示如何使用Callable接口创建多个线程,并让这些线程共享同一个Callable实例(即同一个target对象)来处理同一份资源。 示例场景:多个线程共同对一个计数器进行累加操作。 步骤: 1. 创建一个实现Callable接口的类,其中包含共享资源(如计数器)和具体的任务逻辑(call方法)。 2. 在call方法中实现累加操作,注意使用同步机制(如synchronized关键字或原子类)保证线程安全。 3. 创建多个线程(通过线程池或FutureTask包装)并执行同一个Callable实例。 代码示例:</think>### Java 使用 Callable 接口创建线程及共享资源处理 #### 一、Callable 接口创建线程的基本方法 Callable 接口是 Java 5 引入的增强型线程实现方式,相比 Runnable 有以下优势: - 支持返回值(通过 Future 获取) - 允许抛出受检异常 - 可线程池高效集成 **基本创建步骤**: ```java import java.util.concurrent.*; public class CallableDemo { public static void main(String[] args) throws Exception { // 1. 创建Callable实现类 MyCallable task = new MyCallable(); // 2. 包装为FutureTask(实现RunnableFuture接口) FutureTask<Integer> futureTask = new FutureTask<>(task); // 3. 创建线程并启动 new Thread(futureTask).start(); // 4. 获取执行结果(阻塞直到计算完成) int result = futureTask.get(); System.out.println("计算结果: " + result); } } class MyCallable implements Callable<Integer> { @Override public Integer call() throws Exception { int sum = 0; for (int i = 1; i <= 5; i++) { sum += i; Thread.sleep(100); // 模拟耗时操作 } return sum; // 返回计算结果 } } ``` 输出: ``` 计算结果: 15 ``` #### 二、多线程共享 target 对象处理同一资源 当多个线程共享同一个 Callable 实例时,它们可以协同处理同一份资源,这种模式特别适用于: - 分布式计数器 - 资源池管理 - 并行数据处理 - 状态监控系统 **代码示例:银行账户并行存取款** ```java import java.util.concurrent.*; public class SharedCallableDemo { public static void main(String[] args) throws Exception { // 创建共享的银行账户(Callable实例) BankAccount account = new BankAccount(1000); // 创建线程池 ExecutorService executor = Executors.newFixedThreadPool(3); // 提交存款任务(共享同一个account对象) Future<Integer> deposit1 = executor.submit(account, 200); Future<Integer> deposit2 = executor.submit(account, 300); // 提交取款任务 Future<Integer> withdraw = executor.submit(account, -500); // 获取结果 System.out.println("存款1后余额: " + deposit1.get()); System.out.println("存款2后余额: " + deposit2.get()); System.out.println("取款后余额: " + withdraw.get()); executor.shutdown(); } } class BankAccount implements Callable<Integer> { private int balance; // 共享资源:账户余额 public BankAccount(int initialBalance) { this.balance = initialBalance; } // 同步方法保证线程安全 public synchronized Integer call() throws Exception { // 获取传入的操作金额 int amount = (Integer) FutureTask.class.getDeclaredField("callable") .get(Thread.currentThread().getStackTrace()[2].getClass()); System.out.println(Thread.currentThread().getName() + " 操作: " + (amount > 0 ? "存款" : "取款") + Math.abs(amount)); balance += amount; // 更新余额 Thread.sleep(200); // 模拟处理延时 return balance; // 返回当前余额 } } ``` **输出示例**: ``` pool-1-thread-1 操作: 存款200 pool-1-thread-2 操作: 存款300 pool-1-thread-3 操作: 取款500 存款1后余额: 1200 存款2后余额: 1500 取款后余额: 1000 ``` #### 三、共享 Target 对象的优势分析 1. **资源共享机制**: - 所有线程共享同一实例内存空间 - 状态变更对所有线程立即可见 - 避免数据拷贝开销 2. **同步控制实现**: ```mermaid graph LR A[共享资源] --> B[synchronized方法] A --> C[Lock对象] A --> D[原子类] B --> E[保证原子性] C --> F[更灵活的锁控制] D --> G[无锁高性能] ``` 3. **适用场景对比**: | 场景 | 独立实例 | 共享实例 | |---------------------|-----------------------|-----------------------| | 内存占用 | 高(每线程独立对象) | 低(单对象共享) | | 状态同步 | 需要额外机制 | 自动同步 | | 资源竞争 | 低 | 高(需同步控制) | | 典型应用 | 独立任务处理 | 协作任务/资源池 | #### 四、关键技术要点 1. **线程安全保证**: - 使用 `synchronized` 关键字保护临界区 - 或使用 `ReentrantLock` 实现更灵活的锁控制 - 推荐使用原子类(如 `AtomicInteger`)避免锁竞争 2. **结果获取方式**: ```java // 批量获取结果示例 List<Future<Integer>> results = new ArrayList<>(); for (int i = 0; i < 5; i++) { results.add(executor.submit(sharedTask)); } for (Future<Integer> future : results) { System.out.println("结果: " + future.get()); } ``` 3. **异常处理机制**: ```java try { future.get(); } catch (ExecutionException e) { Throwable cause = e.getCause(); if (cause instanceof InsufficientFundsException) { // 处理自定义异常 } } ``` > 关键优势:通过共享 Callable 实例,多个线程可以**天然共享对象内部状态**,无需额外的线程间通信机制,同时保持代码的面向对象特性[^1][^2]。这种模式将**CPU执行**、**业务逻辑**和**共享数据**清晰分离,符合高内聚低耦合的设计原则[^3][^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值