callable多线程

本文详细对比了Callable与Runnable两个接口的不同之处,包括方法定义、执行结果处理方式等,并介绍了FutureTask类如何作为桥梁连接Callable与Runnable,使得任务既可被执行也能获取结果。

在网上学习后,自我整理一下对callable的理解。

(1)Callable规定的方法是call(),而Runnable规定的方法是run().
(2)Callable的任务执行后可返回值,而Runnable的任务是不能返回值的。
(3)call()方法可抛出异常,而run()方法是不能抛出异常的。
(4)运行Callable任务可拿到一个Future对象, Future表示异步计算的结果。

它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果。
通过Future对象可了解任务执行情况,可取消任务的执行,还可获取任务执行的结果。
Callable是类似于Runnable的接口,实现Callable接口的类和实现Runnable的类都是可被其它线程执行的任务。

FutureTask类实现了RunnableFuture接口

public  interface  RunnableFuture<V> extends Runnable, Future<V> {
    voidrun();
}
 RunnableFuture 继承了 Runnable

可以通过FutureTask获取callable的返回结果

FutureTask中提供了一个以callable作为入参的方法

RunnableFuture继承了Runnable接口和Future接口,而FutureTask实现了RunnableFuture接口。所以它既可以作为Runnable被线程执行,又可以作为Future得到Callable的返回值。
  FutureTask提供了2个构造器:

publicFutureTask(Callable<V> callable) {
}
publicFutureTask(Runnable runnable, V result) {
}
  事实上,FutureTask是Future接口的一个唯一实现类。
要实现 3 个子线程共享处理 100 张票的功能,可以使用 `Callable` 和 `ExecutorService` 来管理多线程任务。`Callable` 是一个接口,它类似于 `Runnable`,但支持返回结果并能抛出异常。通过 `Future` 对象可以获取每个线程的执行结果。 以下是一个完整的解决方案: --- ### 回答问题 #### 使用 `Callable` 实现多线程售票系统 我们可以将售票逻辑封装到 `Callable` 中,并使用 `ExecutorService` 来管理线程池。以下是具体代码实现: ```java import java.util.concurrent.*; public class TicketSystem { private static final int TOTAL_TICKETS = 100; // 总票数 private static final Object lock = new Object(); // 锁对象,用于同步访问 private static int remainingTickets = TOTAL_TICKETS; // 剩余票数 public static void main(String[] args) { ExecutorService executor = Executors.newFixedThreadPool(3); // 创建包含 3 个线程的线程池 Future<Integer>[] futures = new Future[3]; // 存储每个线程的 Future 结果 // 提交 3 个 Callable 任务 for (int i = 0; i < 3; i++) { futures[i] = executor.submit(new TicketCallable()); } // 获取每个线程的售票结果 for (int i = 0; i < 3; i++) { try { System.out.println("Thread " + (i + 1) + " sold " + futures[i].get() + " tickets."); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } } executor.shutdown(); // 关闭线程池 } // 定义 Callable 任务 static class TicketCallable implements Callable<Integer> { @Override public Integer call() { int ticketsSoldByThisThread = 0; while (true) { synchronized (lock) { if (remainingTickets > 0) { ticketsSoldByThisThread++; remainingTickets--; System.out.println(Thread.currentThread().getName() + " sold a ticket. Remaining: " + remainingTickets); } else { break; // 没有剩余票时退出循环 } } } return ticketsSoldByThisThread; // 返回当前线程售出的票数 } } } ``` --- ### 给出解释 1. **线程池创建**: - 使用 `Executors.newFixedThreadPool(3)` 创建了一个包含 3 个线程的线程池。 - 这种方式比手动创建线程更加高效,因为它复用了线程资源。 2. **同步机制**: - 使用 `synchronized(lock)` 确保多个线程对共享资源(`remainingTickets`)的访问是互斥的。 - 这样可以避免多个线程同时修改 `remainingTickets` 导致数据不一致的问题。 3. **Callable 任务**: - `TicketCallable` 类实现了 `Callable<Integer>` 接口,表示每个线程的任务。 - 在 `call()` 方法中,线程会不断尝试售票,直到所有票都被售罄。 4. **Future 获取结果**: - 每个线程的执行结果(售出的票数)通过 `Future.get()` 方法获取。 - 如果某个线程在执行过程中抛出了异常,可以通过 `ExecutionException` 捕获并处理。 5. **线程安全的计数器**: - `remainingTickets` 是一个共享变量,必须通过同步机制来保证其线程安全性。 --- ### 输出示例 运行上述代码后,输出可能如下(由于线程调度顺序不同,每次运行的结果可能略有差异): ``` pool-1-thread-1 sold a ticket. Remaining: 99 pool-1-thread-2 sold a ticket. Remaining: 98 pool-1-thread-3 sold a ticket. Remaining: 97 ... Thread 1 sold 33 tickets. Thread 2 sold 33 tickets. Thread 3 sold 34 tickets. ``` 可以看到,100 张票被 3 个线程公平地分配并售出。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值