• Java多线程之Callable接口与Runnable的实现以及选择


    通过实现Runnable接口的实现

    package Thread;

    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;

    public class RunnableThreadDemo {

    private static int POOL_NUM = 30; // 线程池数量

    public static void main(String[] args) throws InterruptedException {
    ExecutorService executorService = Executors.newFixedThreadPool(10);
    for (int i = 0; i < POOL_NUM; i++) {
    RunnableThread thread = new RunnableThread();
    //线程停顿
    Thread.sleep(1000);
    executorService.execute(thread);
    }
    // 关闭线程池
    executorService.shutdown();
    }

    }

    class RunnableThread implements Runnable {
    @Override
    public void run() {
    System.out.println("通过线程池方式创建的线程Runnable方式:" + Thread.currentThread().getName() + " ");
    }
    }
    通过实现Runnable接口的实现

    package Thread;

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


    public class CallableThreadDemo {

    private static int POOL_NUM = 30; // 线程池数量

    public static void main(String[] args) throws InterruptedException, ExecutionException {
    ExecutorService executorService = Executors.newFixedThreadPool(10);
    for (int i = 0; i < POOL_NUM; i++) {
    Callable<Integer> callableThread = new CallableThread();

    FutureTask<Integer> thread = new FutureTask<Integer>(callableThread);
    //线程停顿
    Thread.sleep(1000);
    //执行 Callable 方式,需要 FutureTask 实现类的支持,用于接收运算结果。 FutureTask 是 Future 接口的实现类
    executorService.submit(thread);

    System.out.println(thread.get());
    }
    // 关闭线程池
    executorService.shutdown();
    }
    }

    class CallableThread implements Callable<Integer> {

    @Override
    public Integer call() throws Exception {
    System.out.println("通过线程池方式创建的线程Callable方式:" + Thread.currentThread().getName() + " ");
    return 10086;
    }
    }

      1.Callable规定的方法是call(),而Runnable规定的方法是run().
      2.Callable的任务执行后可返回值,而Runnable的任务是不能返回值的。  
      3.call() 方法可抛出异常,而run() 方法是不能抛出异常的。 
      4.运行Callable任务可拿到一个Future对象, Future表示异步计算的结果。 
      5.它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果。 
      6.通过Future对象可了解任务执行情况,可取消任务的执行,还可获取任务执行的结果。
      7.Callable是类似于Runnable的接口,实现Callable接口的类和实现Runnable的类都是可被其它线程执行的任务。  

           ExecutorService、Callable都是属于Executor框架。返回结果的线程是在JDK1.5中引入的新特征,还有Future接口也是属于这个框架,有了这种特征得到返回值就很方便了。 
    通过分析可以知道,他同样也是实现了Callable接口,实现了Call方法,所以有返回值。这也就是正好符合了前面所说的两种分类

           执行Callable任务后,可以获取一个Future的对象,在该对象上调用get就可以获取到Callable任务返回的Object了。get方法是阻塞的,即:线程无返回结果,get方法会一直等待。

    再介绍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类。
    ExecutoreService提供了submit()方法,传递一个Callable,或Runnable,返回Future。如果Executor后台线程池还没有完成Callable的计算,这调用返回Future对象的get()方法,会阻塞直到计算完成。
     

    为什么要用线程池:

    1.减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。

    2.可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为消耗过多的内存,而把服务器累趴下(每个线程需要大约1MB内存,线程开的越多,消耗的内存也就越大,最后死机)。

    Java里面线程池的顶级接口是Executor,但是严格意义上讲Executor并不是一个线程池,而只是一个执行线程的工具。真正的线程池接口是ExecutorService。

    题外话,Thread表示一个线程,每个任务都创建一个线程肯定是不妥的,正确的做法应该是初始化一定量的Thread对象,实现Runnable接口创建表示任务的类,并把这些任务对给Thread线程执行。

     
    我们应该是使用Runnable还是Thread?
    Java不支持多继承,但允许实现多个接口。所以如果需要继承其他类,实现Runnable接口是好了。
    ---------------------
    作者:性情中人1993
    来源:CSDN
    原文:https://blog.csdn.net/qq_38765404/article/details/81163959
    版权声明:本文为博主原创文章,转载请附上博文链接!

  • 相关阅读:
    让 vscode 作为 SpringBoot,Java,Maven,甚至于 JavaScript,C,C++,Python,Php等多语言的开发工具吧!
    MySQL 连接错误集锦
    前端开发工具库:包含事件委托,动画处理,以及大部分常用的前端工具
    初探 Node.js 框架:eggjs (环境搭配篇)
    如何快速搭建一个 Node.JS 项目并进入开发?
    关于 JavaSrcipt 前端开发的建议:模块化开发
    Spring-Session 会话共享 -> 基于 Redis 集群,内附各大错误合集,包括配置,类寻找不到、连接错误等
    Java Email 邮件发送
    CSS 显示或隐藏子元素
    Ubuntu美化及配置,常见问题解决方案(仿 Mac 风格)
  • 原文地址:https://www.cnblogs.com/GarfieldEr007/p/10166054.html
Copyright © 2020-2023  润新知