理解java多线程中ExecutorService使用_java

java.util.concurrent包里提供了关于多线程操作的类,平常用的比较多的是ExecutorService及其实现类(如ThreadPoolExecutor等),Executor,Executors,Future,Callable等

1. ExecutorService(继承自Executor)接口:提供了一些异步的多线程操作方法,如execute(), submit(), shutdown(), shutdownNow()等

2. Executor接口:执行提交的任务(线程),只有一个方法 execute(Runnable a)

2. Executors类: 提供了一些工厂方法和一些公共方法来操作Executor子类和ThreadFactory等,如newXXX(),xxxThreadFactory()等

3. Futrue接口:代表了线程执行结果,提供了获取线程执行结果和取消线程的方法,如get(),cancle()等

4. Callable接口:JDK1.5提供的有返回值的线程执行新接口

对ExecutorService和Future的理解做简单记录

代码:

public class Main {
  private static int count = 0;

  public static void main(String[] args){
    List<Future> resultList = new LinkedList<>();

    /**
     * Executors.newCachedThreadPool() 创建一个线程缓存池,若60s中线程没有被使用,则会停止线程并从缓存池中移除
     * Executors.newScheduledThreadPool() 创建一个固定容量的线程池,里边的线程按照设定的调度时间执行
     * Executors.newFixedThreadPool()  拥有固定容量的线程缓存池
     * Executors.newSingleThreadExecutor() 容量为一的线程缓存池,只会有一个线程
     */
    ExecutorService executorService = Executors.newCachedThreadPool();
    for(int i=0; i<10; i++){
      Future future = executorService.submit(new Callable<String>() {
        @Override
        public String call() {
          try {
            System.out.println(Thread.currentThread().getName());
            Thread.sleep(5000);
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
          int count = Main.count;
          System.out.println(Thread.currentThread().getName() + "..start Main count:..." + count);
          Main.count = ++count;
          System.out.println(Thread.currentThread().getName() + "..end Main count:..." + Main.count);
          return Thread.currentThread().getName();
        }
      });
      resultList.add(future);
    }
    executorService.shutdown();
    for(Future future: resultList){
      try {
        System.out.println(future.get() + "..is over...");
      } catch (InterruptedException e) {
        e.printStackTrace();
      } catch (ExecutionException e) {
        e.printStackTrace();
      }
    }
    System.out.println("main thread end...");
  }
}

输出:

pool-1-thread-1
pool-1-thread-2
pool-1-thread-3
pool-1-thread-4
pool-1-thread-5
pool-1-thread-6
pool-1-thread-7
pool-1-thread-8
pool-1-thread-9
pool-1-thread-10
pool-1-thread-1..start Main count:...0
pool-1-thread-2..start Main count:...0
pool-1-thread-3..start Main count:...1
pool-1-thread-2..end Main count:...1
pool-1-thread-1..end Main count:...1
pool-1-thread-3..end Main count:...2
pool-1-thread-1..is over...
pool-1-thread-2..is over...
pool-1-thread-4..start Main count:...2
pool-1-thread-3..is over...
pool-1-thread-4..end Main count:...3
pool-1-thread-4..is over...
pool-1-thread-5..start Main count:...3
pool-1-thread-5..end Main count:...4
pool-1-thread-5..is over...
pool-1-thread-6..start Main count:...4
pool-1-thread-6..end Main count:...5
pool-1-thread-6..is over...
pool-1-thread-7..start Main count:...5
pool-1-thread-7..end Main count:...6
pool-1-thread-7..is over...
pool-1-thread-8..start Main count:...6
pool-1-thread-8..end Main count:...7
pool-1-thread-8..is over...
pool-1-thread-9..start Main count:...7
pool-1-thread-9..end Main count:...8
pool-1-thread-9..is over...
pool-1-thread-10..start Main count:...8
pool-1-thread-10..end Main count:...9
pool-1-thread-10..is over...
main thread end... //主线程在所有线程执行完成后结束

控制台在等待5秒后打印出上边的输出结果,原因是所有的线程启动的时候是一个并发操作,都会去等待5秒,所以整体看来只等了5秒,这是一个并发操作

总结:

1. ExecutorService提供的execute()方法和submit()方法的区别:

  a. execute()方法只接受Runnable类型的实例,所以不能拿到返回值,也不能动态获取线程执行的情况

  b. submit()方法接受Runnable和Callable实例,会返回Future实例,Future实例的get()方法可以获取线程执行返回值,并能抛出线程执行异常。所以如果要获取线程执行返回的结果,并能处理线程执行时可能出现的异常,或者想中途取消线程执行时可以使用submit()方法

2. 通过输出可以看到main方法(主线程)在所有线程执行完成后结束,原因:

  a. 通过submit()方法获取Future实例,并通过Future实例的get()方法获取线程返回结果,而Future实例的get()方法会等待线程执行完毕才会返回,所以main方法会等待所有子线程结束才会结束

  b. 若去掉上边红色标注的for循环,则main方法(主线程)会提前结束,而不会等待所有子线程结束

补充:

1. 多个线程并发执行时,若其中某一个线程出现了异常并且没有被处理,则该线程会自动停止执行,但其他线程还是会正常执行,这就是为什么tomcat请求出现异常时,tomcat还可以继续提供服务的原因。

2. tomcat提供了线程池和等待池,每一个请求过来都会重新启动一个新的线程处理该请求,若线程池中线程用完,再来请求的时候就会放到等待池中等待,当其中有线程释放回线程池中时,就会为等待池中的请求分配线程处理请求。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索java
, 多线程
ExecutorService
java 多线程 executor、java executorservice、java多线程理解、java多线程的理解、深入理解java多线程,以便于您获取更多的相关知识。

时间: 2024-10-03 13:06:54

理解java多线程中ExecutorService使用_java的相关文章

java多线程中的volatile和synchronized用法分析_java

本文实例分析了java多线程中的volatile和synchronized用法.分享给大家供大家参考.具体实现方法如下: 复制代码 代码如下: package com.chzhao; public class Volatiletest extends Thread {     private static int count = 0;     public void run() {         count++;     }     public static void main(String

关于java多线程中的join方法

问题描述 关于java多线程中的join方法 1.主线程可能在子线程结束之前 结束吗?如果可能的话 举一个例子 2.如何理解join方法, 结合实际应用. 非常感谢非常感谢!!! 解决方案 关于join,参考:http://www.blogjava.net/jnbzwm/articles/330549.html 解决方案二: 主线程可能在子线程结束之前 结束吗 一般来说不可以,但是也不一定,如果子线程在执行finally中的代码,应该会等它执行完了才退出. 晕,join方法和什么"让主线程等子线

多线程问题-新手求助关于Java多线程中启动线程问题

问题描述 新手求助关于Java多线程中启动线程问题 public class Example15_1 { /** * @param args */public static void main(String[] args) { // TODO Auto-generated method stub SpeakHello speakHello; SpeakNinhao speakNinhao; speakHello = new SpeakHello(); speakNinhao= new Speak

java多线程中两个容器之间的同步

问题描述 java多线程中两个容器之间的同步 写了一个多线程的爬虫(对多线程不熟悉),但是每次队列中都有重复的元素,我把代码逻辑贴上来,大家帮我看一下,谢谢了: 在进程中: queue = LinkedBlockingQueue set = ConcurrentSkipListSet 在每个进程中使用了bfs bfs: while(!queue.empty()){ s = queue.poll() //...逻辑代码 set.add(s) //对s所有子状态扩展 for(son : s.sons

Java多线程中的ThreadLocal,可继承,可修改

Java多线程中的ThreadLocal,可继承,可修改. package test; import java.util.Date; public class InheritableThreadLocalExt extends InheritableThreadLocal<Object>{ @Override protected Object initialValue() { return new Date().getTime(); } @Override protected Object c

深入探讨Java多线程中的volatile变量_java

volatile 变量提供了线程的可见性,并不能保证线程安全性和原子性. 什么是线程的可见性: 锁提供了两种主要特性:互斥(mutual exclusion) 和可见性(visibility).互斥即一次只允许一个线程持有某个特定的锁,因此可使用该特性实现对共享数据的协调访问协议,这样,一次就只有一个线程能够使用该共享数据.可见性要更加复杂一些,它必须确保释放锁之前对共享数据做出的更改对于随后获得该锁的另一个线程是可见的 -- 如果没有同步机制提供的这种可见性保证,线程看到的共享变量可能是修改前

java多线程中的异常处理机制简析_java

在java多线程程序中,所有线程都不允许抛出未捕获的checked exception,也就是说各个线程需要自己把自己的checked exception处理掉.这一点是通过java.lang.Runnable.run()方法声明(因为此方法声明上没有throw exception部分)进行了约束.但是线程依然有可能抛出unchecked exception,当此类异常跑抛出时,线程就会终结,而对于主线程和其他线程完全不受影响,且完全感知不到某个线程抛出的异常(也是说完全无法catch到这个异常

深入理解Java编程中异常处理的优劣_java

Java编程中的异常处理是一个很常见的话题了,几乎任何一门介绍性的Java课程都会提到异常处理.不过,我认为很多人其实没有真正掌握正确处理异常情况的方法和策略,最多也就不过了解个大概,知道概念.我想对三种不同程度和质量的Java异常处理进行了讨论,所阐述的处理异常的方式按手法的高下分为:好,不好和恶劣三种.同时提供了一些解决这些问题的技巧.首先解释一些java异常处理中必须搞清楚的定义和机制.Java语言规范将自Error类或RuntimeException类衍生出来的任何违例都称作"不可检查&

java多线程中使用同步那它和单线程有什么区别?

问题描述 如果在多线程中使用同步synchronized比如有100个线程,所有线程都要一个一个的执行,那这和单线程不是一样了吗?并且多线程同步的时候操作系统来回的检查锁的状态倒浪费了性能,我理解的是不是哪里不对啊,请知道的帮解答一下,还有就是关于同步有很多方法,是不是都一回事只要会一种就行啊比如我就知道在run里synchronized(obj)这样 解决方案 解决方案二:它们的目的是相同的,都可以很好控制程序执行流程:多线程是为了提高CPU的利用率,在某个线程高速缓存或者执行等待时,可以通知