03.Java基础(线程池和Callable<T>)

简介: 在以往的工作中,创建线程通常我们关注的都是Thread或者Runnable为主,其实忽略了另外一个比较有用的创建线程的方式,就是Callable接口,下边是Callable配合线程池实现异步任务import java.

在以往的工作中,创建线程通常我们关注的都是Thread或者Runnable为主,其实忽略了另外一个比较有用的创建线程的方式,就是Callable接口,下边是Callable配合线程池实现异步任务

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class CallableDemo {

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        ExecutorService pool = Executors.newCachedThreadPool();
        Future<Object> future = pool.submit(new MyCallable());
        //通过get方法获取执行结果,该方法会阻塞直到任务返回结果
        Object obj = future.get();
        System.out.println(obj.toString());
    }

}

class MyCallable implements Callable<Object>{

    @Override
    public Object call() throws Exception {
        System.out.println("执行callable3");
        return "right";
    }
    
}

在Java中,创建线程一般有两种方式,一种是继承Thread类,一种是实现Runnable接口。然而,这两种方式的缺点是在线程任务执行结束后,无法获取执行结果。我们一般只能采用共享变量或共享存储区以及线程通信的方式实现获得任务结果的目的。
不过,Java中,也提供了使用Callable和Future来实现获取任务结果的操作。Callable用来执行任务,产生结果,而Future用来获得结果。

可以看到,与Runnable接口不同之处在于,call方法带有泛型返回值V。

我们通过简单的例子来体会使用Callable和Future来获取任务结果的用法。
假设我们现在有一个任务,要计算出1-10000之间的所有数字的和,为了提升计算速度,我们使用两个线程,第一个线程计算1-5000的和,另外有一个线程计算5001-10000之间的数字的和。为了更好的展示效果,让每个线程在计算过程中休眠5s。

示例程序来自网友:

    import java.util.ArrayList;  
    import java.util.concurrent.Callable;  
    import java.util.concurrent.ExecutionException;  
    import java.util.concurrent.ExecutorService;  
    import java.util.concurrent.Executors;  
    import java.util.concurrent.Future;  
      
    public class TestMain{  
        public static void main(String[] args) throws InterruptedException, ExecutionException {  
            ExecutorService executor = Executors.newCachedThreadPool();  
            ArrayList<Future<Integer>> resultList = new ArrayList<>();  
              
            //创建并提交任务1  
            AddNumberTask task1 = new AddNumberTask(1, 5000);  
            Future<Integer> future1 = executor.submit(task1);  
            resultList.add(future1);  
              
            //创建并提交任务2  
            AddNumberTask task2 = new AddNumberTask(5001, 10000);  
            Future<Integer> future2 = executor.submit(task2);  
            resultList.add(future2);  
              
            executor.shutdown();  
              
            int total = 0;  
              
            for(Future<Integer> future : resultList){  
                while(true){  
                    if(future.isDone() && !future.isCancelled()){  
                        int sum = future.get();  
                        total += sum;  
                        break;  
                    }  
                    else{  
                        Thread.sleep(100);  
                    }  
                }  
            }  
              
            System.out.println("total sum is " + total);  
        }  
      
    }  
      
    class AddNumberTask implements Callable<Integer>{  
        private int start;  
        private int end;  
          
        public AddNumberTask(int start, int end) {  
            // TODO Auto-generated constructor stub  
            this.start = start;  
            this.end = end;  
        }  
          
        @Override  
        public Integer call() throws Exception {  
            // TODO Auto-generated method stub  
            int totalSum = 0;  
              
            for(int i = start; i <= end; i++){  
                totalSum += i;  
            }  
              
            Thread.sleep(5000);  
              
            return totalSum;  
        }  
          
    }  
相关文章
|
1天前
|
Java 开发者
奇迹时刻!探索 Java 多线程的奇幻之旅:Thread 类和 Runnable 接口的惊人对决
【8月更文挑战第13天】Java的多线程特性能显著提升程序性能与响应性。本文通过示例代码详细解析了两种核心实现方式:Thread类与Runnable接口。Thread类适用于简单场景,直接定义线程行为;Runnable接口则更适合复杂的项目结构,尤其在需要继承其他类时,能保持代码的清晰与模块化。理解两者差异有助于开发者在实际应用中做出合理选择,构建高效稳定的多线程程序。
16 7
|
3天前
|
消息中间件 Java 大数据
"深入理解Kafka单线程Consumer:核心参数配置、Java实现与实战指南"
【8月更文挑战第10天】在大数据领域,Apache Kafka以高吞吐和可扩展性成为主流数据流处理平台。Kafka的单线程Consumer因其实现简单且易于管理而在多种场景中受到欢迎。本文解析单线程Consumer的工作机制,强调其在错误处理和状态管理方面的优势,并通过详细参数说明及示例代码展示如何有效地使用KafkaConsumer类。了解这些内容将帮助开发者优化实时数据处理系统的性能与可靠性。
23 7
|
2天前
|
安全 Java 数据处理
Java并发编程:解锁多线程的潜力
在数字化时代的浪潮中,Java作为一门广泛使用的编程语言,其并发编程能力是提升应用性能和响应速度的关键。本文将带你深入理解Java并发编程的核心概念,探索如何通过多线程技术有效利用计算资源,并实现高效的数据处理。我们将从基础出发,逐步揭开高效并发编程的面纱,让你的程序运行得更快、更稳、更强。
|
19小时前
|
缓存 监控 Java
Java性能优化:从单线程执行到线程池管理的进阶实践
在Java开发中,随着应用规模的不断扩大和用户量的持续增长,性能优化成为了一个不可忽视的重要课题。特别是在处理大量并发请求或执行耗时任务时,单线程执行模式往往难以满足需求,这时线程池的概念便应运而生。本文将从应用场景举例出发,探讨Java线程池的使用,并通过具体案例和核心代码展示其在实际问题解决中的强大作用。
|
2天前
|
缓存 Java 数据处理
Java中的并发编程:解锁多线程的力量
在Java的世界里,并发编程是提升应用性能和响应能力的关键。本文将深入探讨Java的多线程机制,从基础概念到高级特性,逐步揭示如何有效利用并发来处理复杂任务。我们将一起探索线程的创建、同步、通信以及Java并发库中的工具类,带你领略并发编程的魅力。
|
2天前
|
Java
Java线程池核心数为0时,线程池如何执行?
【8月更文挑战第11天】Java线程池核心数为0时,线程池如何执行?
12 1
|
4天前
|
Java 调度 开发者
Java并发编程:解锁多线程同步的奥秘
在Java的世界里,并发编程是提升应用性能的关键所在。本文将深入浅出地探讨Java中的并发工具和同步机制,带领读者从基础到进阶,逐步掌握多线程编程的核心技巧。通过实例演示,我们将一起探索如何在多线程环境下保持数据的一致性,以及如何有效利用线程池来管理资源。无论你是初学者还是有一定经验的开发者,这篇文章都将为你打开新的视野,让你对Java并发编程有更深入的理解和应用。
|
2天前
|
安全 Java API
揭秘Java并发编程的神秘面纱:线程安全与性能优化之间的微妙舞蹈,如何让你的程序在多核时代中翱翔!
【8月更文挑战第12天】随着多核处理器的普及,Java并发编程越发重要。线程安全确保多线程环境下的程序一致性,而性能优化则让程序高效运行。通过同步机制如`synchronized`关键字或`ReentrantLock`接口,我们可以实现线程安全,如在银行账户存款操作中限制并发访问。然而,过度同步会导致性能下降,因此采用细粒度锁和利用Java并发工具类(如`ConcurrentHashMap`)可提高程序的并发能力。理解这些概念并加以实践,是每个Java开发者提升技能的关键。
|
3天前
|
调度 Python
python3 多线程中使用线程睡眠
8月更文挑战第11天
13 3
|
5天前
|
安全 算法 Java
17 Java多线程(线程创建+线程状态+线程安全+死锁+线程池+Lock接口+线程安全集合)(下)
17 Java多线程(线程创建+线程状态+线程安全+死锁+线程池+Lock接口+线程安全集合)
34 6
下一篇
云函数