当前位置: 首页 > news >正文

网站正在建设中页面 英文dedecms5.7化妆品公司网站源码

网站正在建设中页面 英文,dedecms5.7化妆品公司网站源码,方案公司,WordPress文怎么写文章目录 1. 为什么要使用线程池2. 线程池的核心参数和线程池的执行原理2.1 线程池的核心参数2.2 线程池的执行原理 3. 线程池中常见的阻塞队列3.1 常见的阻塞队列3.2 ArrayBlockingQueue 和 LinkedBlockingQueue 的区别 4. 如何确定线程池的核心线程数4.1 应用程序中任务的类型… 文章目录 1. 为什么要使用线程池2. 线程池的核心参数和线程池的执行原理2.1 线程池的核心参数2.2 线程池的执行原理 3. 线程池中常见的阻塞队列3.1 常见的阻塞队列3.2 ArrayBlockingQueue 和 LinkedBlockingQueue 的区别 4. 如何确定线程池的核心线程数4.1 应用程序中任务的类型4.1.1 IO 密集型任务4.1.2 CPU 密集型任务 4.2 如何确定核心线程数 5. 线程池的种类5.1 固定线程数的线程池5.2 单线程线程池5.3 可缓存线程池5.4 提供延迟功能和周期执行功能的线程池 6. 为什么不建议使用 Executors 类提供的静态方法创建线程池7. 线程池多线程的使用场景7.1 CountDownLatch7.2 多线程使用场景一ElasticSearch 批量导入数据7.3 多线程使用场景二数据汇总7.4 多线程使用场景三异步调用 8. 控制某个方法允许线程并发访问的线程数量Semaphore9. ThreadLocal9.1 ThreadLocal的基本使用9.2 ThreadLocal的实现原理源码分析9.2.1 set 方法9.2.2 get 方法9.2.3 remove 方法 9.3 ThreadLocal 的内存泄漏问题 10. 线程池的 execute 方法和 submit 方法有什么区别10.1 返回值10.2 异常处理10.3 任务类型10.4 使用场景 1. 为什么要使用线程池 我们为什么要使用线程池呢主要有两个原因 每次创建线程的时候都会占用一定的内存空间如果要创建很多个线程有可能会浪费内存严重的情况下还有可能会导致内存溢出CPU 资源是有限的同一时刻 CPU 只能处理一个线程如果有大量的请求到达服务器我们创建了大量的线程那么很多线程都没有 CPU 的执行权这些线程都需要等待获取 CPU 的执行权在这个过程中会有非常多的切换线程操作频繁的线程切换操作会导致上下文切换开销增大CPU 花费在真正执行任务上的时间就会减少从而导致程序的性能下降 在项目开发的过程中一般都会用线程池来管理线程、创建线程 线程池相关的内容跟实际开发是有很大关系的面试官也是特别喜欢问 2. 线程池的核心参数和线程池的执行原理 2.1 线程池的核心参数 线程池的核心参数主要有七个我们主要参考 ThreadPoolExecutor 类的具有七个参数的构造函数这七个参数也是面试官提问的重点 corePoolSize核心线程数maximumPoolSize最大线程数核心线程数 救急线程数的最大值keepAliveTime救急线程的生存时间如果生存时间内没有新任务与救急线程相关的资源会被释放unit救急线程的生存时间单位workQueue当没有空闲的核心线程时新来任务会加入到此队列中排队如果队列满了会创建救急线程来执行任务threadFactory线程工厂可以定制如何线程对象例如为线程设置名字、是否为守护线程等handler拒绝策略当所有线程都在繁忙、workQueue 中的线程也满了时会触发拒绝策略 2.2 线程池的执行原理 下面为大家介绍一下线程池的执行原理也就是线程池是怎么工作的 首先当有一个新任务到来时会先判断核心线程数是否已经满了如果核心线程数没满就将任务添加到工作线程中执行这个任务 如果核心线程数已经满了会判断阻塞队列是否满了如果阻塞队列中还有空间就把任务添加到阻塞队列中进行等待 如果阻塞队列满了会判断线程数是否小于最大线程数如果线程数小于最大线程数会创建救急线程来执行任务 当核心线程或救急线程处于空闲的时候会去阻塞队列中检查一下是否有需要执行的任务如果有就会使用核心线程或救急线程来执行阻塞队列中的任务 假如所有条件都不满足线程池会有一个拒绝策略拒绝策略有以下四种 AbortPolicy直接抛出异常默认使用的拒绝策略CallerRunsPolicy用调用者所在的线程来执行任务DiscardOldestPolicy丢弃阻塞队列中靠最前的任务并执行当前任务DiscardPolicy直接丢弃任务 可以运行以下代码查看控制台的输出辅助理解线程池的执行原理 import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.FutureTask; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger;public class TestThreadPoolExecutor {static class MyTask implements Runnable {private final String name;private final long duration;public MyTask(String name) {this(name, 0);}public MyTask(String name, long duration) {this.name name;this.duration duration;}Overridepublic void run() {try {System.out.println(Thread.currentThread().getName() Running... this);Thread.sleep(duration);} catch (InterruptedException exception) {exception.printStackTrace();}}Overridepublic String toString() {return MyTask( name );}}public static void main(String[] args) {AtomicInteger atomicInteger new AtomicInteger(1);ArrayBlockingQueueRunnable arrayBlockingQueue new ArrayBlockingQueue(2);ThreadPoolExecutor threadPool new ThreadPoolExecutor(2,3,0,TimeUnit.MILLISECONDS,arrayBlockingQueue,runnable - new Thread(runnable, myThread atomicInteger.getAndIncrement()),new ThreadPoolExecutor.AbortPolicy());// new ThreadPoolExecutor.CallerRunsPolicy());// new ThreadPoolExecutor.DiscardOldestPolicy());// new ThreadPoolExecutor.DiscardPolicy());showState(arrayBlockingQueue, threadPool);threadPool.submit(new MyTask(1, 3600000));showState(arrayBlockingQueue, threadPool);threadPool.submit(new MyTask(2, 3600000));showState(arrayBlockingQueue, threadPool);threadPool.submit(new MyTask(3));showState(arrayBlockingQueue, threadPool);threadPool.submit(new MyTask(4));showState(arrayBlockingQueue, threadPool);threadPool.submit(new MyTask(5, 3600000));showState(arrayBlockingQueue, threadPool);threadPool.submit(new MyTask(6));showState(arrayBlockingQueue, threadPool);}private static void showState(ArrayBlockingQueueRunnable queue, ThreadPoolExecutor threadPool) {try {Thread.sleep(300);} catch (InterruptedException exception) {exception.printStackTrace();}ListObject tasks new ArrayList();for (Runnable runnable : queue) {try {Field callable FutureTask.class.getDeclaredField(callable);callable.setAccessible(true);Object adapter callable.get(runnable);Class? clazz Class.forName(java.util.concurrent.Executors$RunnableAdapter);Field task clazz.getDeclaredField(task);task.setAccessible(true);Object object task.get(adapter);tasks.add(object);} catch (Exception exception) {exception.printStackTrace();}}System.err.println(pool size: threadPool.getPoolSize() , queue: tasks);}}如果运行代码时遇到了以下错误运行前可以添加以下 VM 参数 错误信息 java.lang.reflect.InaccessibleObjectException: Unable to make field private java.util.concurrent.Callable java.util.concurrent.FutureTask.callable accessible: module java.base does not opens java.util.concurrent to unnamed module 4fca772dat java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:354)at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297)at java.base/java.lang.reflect.Field.checkCanSetAccessible(Field.java:178)at java.base/java.lang.reflect.Field.setAccessible(Field.java:172)VM 参数的具体内容 --add-opens java.base/java.util.concurrentALL-UNNAMED 3. 线程池中常见的阻塞队列 workQueue当没有空闲的核心线程时新来任务会加入到阻塞队列阻塞队列满了后会创建救急线程执行任务 3.1 常见的阻塞队列 常见的阻塞队列主要有以下四种重点了解 ArrayBlockingQueue 和 LinkedBlockingQueue ArrayBlockingQueue基于数组结构的有界阻塞队列符合队列的先进先出原则LinkedBlockingQueue基于链表结构的有界阻塞队列符合队列的先进先出原则DelayedWorkQueue优先级队列能够保证每次出队的元素是队列中延迟时间最短的任务SynchronousQueue不存储元素的阻塞队列每次执行插入操作前都必须等待一个移出操作 补充任何想要放入 DelayedWorkQueue 的对象都必须实现 Delayed 接口Delayed 接口要求实现两个方法 getDelay(TimeUnit unit) 方法用于返回元素的剩余延迟时间即距离执行时间还有多长时间compareTo(Delayed other) 方法用于比较两个 Delayed 对象的延迟时间 3.2 ArrayBlockingQueue 和 LinkedBlockingQueue 的区别 LinkedBlockingQueue推荐使用ArrayBlockingQueue默认无界Integer 类型的最大值支持有界强制有界底层的数据结构是链表底层的数据结构是数组是懒惰的创建节点的时候添加数据提前初始化 Node 数组入队会生成新 NodeNode 需要提前创建好的两把锁链表的头部和尾部各一把锁一把锁 4. 如何确定线程池的核心线程数 4.1 应用程序中任务的类型 应用程序中任务的类型主要可以分为两种 IO 密集型任务CPU 密集型任务 4.1.1 IO 密集型任务 常见的 IO 密集型任务主要有文件读写、数据库读写、网络请求等 4.1.2 CPU 密集型任务 常见的 CPU 密集型任务主要有计算较为密集的代码、BitMap 转换、JSON 转换等 4.2 如何确定核心线程数 对于 IO 密集型的任务来说核心线程数可以设置为 2 * N 1 其中 N 为 CPU 的核数因为 IO 密集型任务消耗的 CPU 资源较少 对于 CPU 密集型的任务来说核心线程数可以设置为 N 1 其中 N 为 CPU 的核数因为 CPU 密集型任务需要消耗大量的 CPU 资源线程数少了就能够减少 CPU 在不同线程之间切换所耗费的时间充分地利用 CPU 资源 一般来说用 Java 开发的应用程序任务的类型大都为 IO 密集型 如何查看电脑的 CPU 核数呢可以运行以下代码查看 public class ProcessorsDemo {public static void main(String[] args) {System.out.println(Runtime.getRuntime().availableProcessors());}}5. 线程池的种类 在 java.util.concurrent.Executors 类中提供了大量创建连接池的静态方法常见的有四种 创建使用固定线程数的线程池创建单线程线程池创建可缓存线程池创建提供延迟功能和周期执行功能的线程池 5.1 固定线程数的线程池 我们可以查看创建固定线程数线程池的源码 固定线程数的线程池的特点是 核心线程数与最大线程数一样没有救急线程阻塞队列是 LinkedBlockingQueue 最大容量为 Integer.MAX_VALUE 固定线程数的线程池适用于任务量已知、耗时较长的任务 import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors;public class FixedThreadPoolCase {static class FixedThreadDemo implements Runnable {Overridepublic void run() {String threadName Thread.currentThread().getName();for (int i 0; i 2; i) {System.out.println(threadName : i);}}}public static void main(String[] args) throws InterruptedException {// 创建一个固定大小的线程池核心线程数和最大线程数都是3ExecutorService executorService Executors.newFixedThreadPool(3);for (int i 0; i 5; i) {executorService.submit(new FixedThreadDemo());Thread.sleep(10);}executorService.shutdown();}}5.2 单线程线程池 单线程线程池只会用唯一的工作线程来执行任务保证所有任务按照先进先出的顺序FIFO执行 我们可以查看创建单线程线程池的源码 单线程线程池的特点是 核心线程数和最大线程数都是1阻塞队列是LinkedBlockingQueue 最大容量为Integer.MAX VALUE 单线程线程池适用于需要严格按照顺序执行的任务 import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors;public class SingleThreadCase {static int count 0;static class Demo implements Runnable {Overridepublic void run() {count;System.out.println(Thread.currentThread().getName() : count);}}public static void main(String[] args) throws InterruptedException {// 单个线程池核心线程数和最大线程数都是1ExecutorService executorService Executors.newSingleThreadExecutor();for (int i 0; i 10; i) {executorService.execute(new Demo());Thread.sleep(5);}executorService.shutdown();}}5.3 可缓存线程池 我们可以查看创建可缓存线程池的源码 可缓存线程池的特点 核心线程数为 0最大线程数是 Integer.MAX VALUE阻塞队列为 SynchronousQueue不存储元素的阻塞队列每个插入操作都必须等待一个移出操作 可缓存线程池适用于任务数比较密集但每个任务执行时间较短的情况 import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors;public class CachedThreadPoolCase {static class Demo implements Runnable {Overridepublic void run() {String threadName Thread.currentThread().getName();try {// 修改睡眠时间模拟线程执行需要花费的时间Thread.sleep(100);System.out.println(threadName 执行完了);} catch (InterruptedException interruptedException) {interruptedException.printStackTrace();}}}public static void main(String[] args) throws InterruptedException {// 创建一个缓存的线程没有核心线程数最大线程数为Integer.MAX_VALUEExecutorService executorService Executors.newCachedThreadPool();for (int i 0; i 10; i) {executorService.execute(new Demo());Thread.sleep(1);}executorService.shutdown();}}5.4 提供延迟功能和周期执行功能的线程池 我们可以查看创建提供延迟功能和周期执行功能的线程池的源码 顾名思义提供延迟功能和周期执行功能的线程池适用于需要延迟执行或周期执行的任务 import java.util.Date; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit;public class ScheduledThreadPoolCase {static class Task implements Runnable {Overridepublic void run() {try {String threadName Thread.currentThread().getName();System.out.println(threadName , 开始 new Date());Thread.sleep(1000);System.out.println(threadName , 结束 new Date());} catch (InterruptedException interruptedException) {interruptedException.printStackTrace();}}}public static void main(String[] args) throws InterruptedException {// 按照周期执行的线程池核心线程数为2最大线程数为Integer.MAX_VALUEScheduledExecutorService scheduledThreadPool Executors.newScheduledThreadPool(2);System.out.println(程序开始 new Date());/** schedule方法提交任务到线程池中* 第一个参数提交的任务* 第二个参数任务执行的延迟时间* 第三个参数时间单位*/scheduledThreadPool.schedule(new Task(), 0, TimeUnit.SECONDS);scheduledThreadPool.schedule(new Task(), 1, TimeUnit.SECONDS);scheduledThreadPool.schedule(new Task(), 5, TimeUnit.SECONDS);Thread.sleep(5000);// 关闭线程池scheduledThreadPool.shutdown();}}6. 为什么不建议使用 Executors 类提供的静态方法创建线程池 阿里开发手册《Java开发手册-嵩山版》中指出 7. 线程池多线程的使用场景 7.1 CountDownLatch CountDownLatch闭锁、倒计时锁用来进行线程同步协作等待所有线程完成倒计时一个或者多个线程等待其他多个线程完成某件事情之后才能执行 构造参数用来初始化等待计数值await()方法用来等待计数归零countDown()方法用来让计数减一 import java.util.concurrent.CountDownLatch;public class CountDownLatchDemo {public static void main(String[] args) throws InterruptedException {// 初始化了一个参数为 3 的倒计时锁CountDownLatch countDownLatch new CountDownLatch(3);new Thread(() - {System.out.println(Thread.currentThread().getName() -begin...);try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}countDownLatch.countDown();System.out.println(Thread.currentThread().getName() -end... countDownLatch.getCount());}).start();new Thread(() - {System.out.println(Thread.currentThread().getName() -begin...);try {Thread.sleep(2000);} catch (InterruptedException e) {throw new RuntimeException(e);}countDownLatch.countDown();System.out.println(Thread.currentThread().getName() -end... countDownLatch.getCount());}).start();new Thread(() - {System.out.println(Thread.currentThread().getName() -begin...);try {Thread.sleep(1500);} catch (InterruptedException e) {throw new RuntimeException(e);}countDownLatch.countDown();System.out.println(Thread.currentThread().getName() -end... countDownLatch.getCount());}).start();String threadName Thread.currentThread().getName();System.out.println(threadName -waiting...);// 等待其他线程完成countDownLatch.await();System.out.println(threadName -wait end...);}}7.2 多线程使用场景一ElasticSearch 批量导入数据 在项目上线之前我们需要把数据库中的数据一次性的同步到 ElasticSearch 索引库中但数据量达到百万级别时一次性读取数据的做法是不可取的Out Of Memory 可以使用线程池的方式导入利用 CountDownLatch 来控制就能避免一次性加载过多防止内存溢出 7.3 多线程使用场景二数据汇总 在一个电商网站中用户下单之后需要查询数据数据包含了三部分订单信息、包含的商品、物流信息 这三块信息都在不同的微服务中进行实现的我们如何完成这个业务呢 我们先来看一下常规的方案先查询订单信息、再查询商品信息、最后查询物流信息整个流程中每个部分是串行化执行的 我们先来看使用多线程的方案查询订单信息、查询商品信息、查询物流信息三个操作相当于同时进行整个流程中每个部分是并发执行的 当然如果采用多线程的方案需要使用 Future 接口execute方法执行后会返回一个结果结果的类型为 Future 接口 7.4 多线程使用场景三异步调用 在很多软件中都会有搜索功能比如电商网站、地图软件等并且这些软件会保存你的搜索记录 我们在实现搜索功能的时候往往不会让保存搜索记录的操作影响到用户的正常搜索 我们可以选择采用异步线程来完成搜索记录的保存操作具体要怎么操作呢当用户开始搜索以后我们正常返回与用户搜索内容相关的数据用另一个线程去保存客户的搜索记录 那在代码中该如何实现呢在 SpringBoot 项目中只需要在保存用户搜索记录的具体方法上添加 Async 注解 /*** 保存用户的搜索记录** param userId Integer* param keyword String*/ Async(taskExecutor) Override public void insert(Integer userId, String keyword) {// 保存用户的搜索记录log.info(用户搜索记录保存成功,用户id:{},关键字:{}, userId, keyword); }同时 Async 注解还能指定使用哪个线程池该线程池需要由 Spring 管理 import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;import java.util.concurrent.ExecutorService; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger;Configuration public class ThreadPoolConfig {/*** 核心线程池大小*/private static final int CORE_POOL_SIZE 25;/*** 最大可创建的线程数*/private static final int MAX_POOL_SIZE 50;/*** 队列最大长度*/private static final int QUEUE_CAPACITY 1000;/*** 线程池维护线程所允许的空闲时间*/private static final int KEEP_ALIVE_SECONDS 500;Bean(taskExecutor)public ExecutorService executorService() {AtomicInteger atomicInteger new AtomicInteger(1);LinkedBlockingQueueRunnable linkedBlockingQueue new LinkedBlockingQueueRunnable(QUEUE_CAPACITY);return new ThreadPoolExecutor(CORE_POOL_SIZE,MAX_POOL_SIZE,KEEP_ALIVE_SECONDS,TimeUnit.MILLISECONDS,linkedBlockingQueue,runnable - new Thread(runnable, wuyanzu-pool- atomicInteger.getAndIncrement()),new ThreadPoolExecutor.DiscardPolicy());}}其中 ExecutorService 类是与线程池相关的类的顶层接口IDEA 中按下 CTRL H 快捷键可查看继承结构 注意事项如果想让 Async 注解生效需要在 SpringBoot 的启动类上添加 EnableAsync 注解 8. 控制某个方法允许线程并发访问的线程数量Semaphore Semaphore信号量JUC 包下的一个工具类实现原理基于 AQS可以通过 Semaphore 类限制执行的线程数量 Semaphore 通常用于那些资源有明确访问数量限制的场景常用于限流 Semaphore的使用步骤 创建 Semaphore 对象并给定一个容量semaphore.acquire()请求一个信号量这时候的信号量个数 - 1一旦没有可使用的信号量也即信号量个数变为负数时再次请求的时候就会阻塞直到其他线程释放了信号量semaphore.release()释放一个信号量此时信号量个数 1 代码示例 import java.util.concurrent.Semaphore;public class SemaphoreCase {public static void main(String[] args) {// 1.创建 semaphore 对象Semaphore semaphore new Semaphore(3);// 2.让 10 个线程同时运行for (int i 0; i 10; i) {new Thread(() - {try {// 3. 获取许可计数 - 1semaphore.acquire();} catch (InterruptedException interruptedException) {interruptedException.printStackTrace();}try {System.out.println(running...);try {Thread.sleep(1000);} catch (InterruptedException interruptedException) {interruptedException.printStackTrace();}System.out.println(end...);} finally {// 4. 释放许可 计数 1semaphore.release();}}).start();}}}9. ThreadLocal ThreadLocal 是多线程中对于解决线程安全的一个操作类它会为每个线程都分配一个独立的线程副本从而解决了变量并发访问冲突的问题ThreadLocal 同时实现了线程内的资源共享 例如使用 JDBC 操作数据库时会将每一个线程的 Connection 对象放入各自的 ThreadLocal 中从而保证每个线程都在各自的 Connection 上进行数据库的操作避免 A 线程关闭了 B 线程的连接 9.1 ThreadLocal的基本使用 ThreadLocal 的基本使用 set(value)设置值get()获取值remove()清除值 代码示例 public class ThreadLocalTest {static ThreadLocalString threadLocal new ThreadLocal();public static void main(String[] args) {new Thread(() - {String threadName Thread.currentThread().getName();threadLocal.set(Tom);removeAfterPrint(threadName);System.out.println(threadName -after remove : threadLocal.get());}, t1).start();new Thread(() - {String threadName Thread.currentThread().getName();threadLocal.set(Jerry);removeAfterPrint(threadName);System.out.println(threadName -after remove : threadLocal.get());}, t2).start();}static void removeAfterPrint(String str) {// 打印当前线程中本地内存中本地变量的值System.out.println(str : threadLocal.get());// 清除本地内存中的本地变量threadLocal.remove();}}9.2 ThreadLocal的实现原理源码分析 ThreadLocal 本质来说就是一个线程内部存储类让每个线程只操作自己内部的值从而实现线程数据隔离 9.2.1 set 方法 9.2.2 get 方法 9.2.3 remove 方法 整体逻辑与 get 方法类似找到目标元素后将其清除 9.3 ThreadLocal 的内存泄漏问题 在分析 ThreadLocal 的内存泄漏问题前我们先来简单了解一下 Java 中的强引用和弱引用 强引用最普通的引用方式表示一个对象处于有用且必须的状态如果一个对象具有强引用则 GC 并不会回收它。即使堆内存不足宁可抛出 OOMOut Of Memory 错误也不会对其进行回收 弱引用表示一个对象处于可能有用且非必须的状态在 GC 线程扫描内存区域时一旦发现弱引用就会回收与弱引用相关联的对象。对于弱引用的回收无论内存区域是否足够一旦发现就会回收 每一个 Thread内部都维护一个了 ThreadLocalMap 在 ThreadLocalMap 中的 Entry 对象继承了 WeakReference 其中 key 为使用弱引用的 ThreadLocal 实例value 为线程变量的副本 以下是 ThreadLocal 类的部分源码 那怎么样防止内存泄漏呢非常简单就是在用完 ThreadLocal 类之后主动调用 ThreadLocal 类的 remove 方法把数据清理掉就能避免内存泄露的情况了 10. 线程池的 execute 方法和 submit 方法有什么区别 在 Java 的ExecutorService接口中execute() 方法和submit(Runnable task)方法是都用来提交任务以供异步执行的但它们之间有一些关键的区别 10.1 返回值 execute(Runnable command)方法没有返回值。它简单地执行给定的Runnable任务不提供关于任务执行状态或结果的信息submit(Runnable task)方法返回一个Future对象通过这个对象可以检查任务是否执行完成并且可以取消任务的执行。但是由于Runnable接口不返回结果所以返回的Future对象在get()方法调用时将返回null 以下是 submit 方法和 execute 方法的源码 注意事项 submit 方法是 ExecutorService 接口提供的execute 方法是由 Executor 接口提供的ExecutorService 接口继承了 Executor 接口 submit 方法 execute 方法 10.2 异常处理 如果在Runnable任务中抛出了未捕获的异常execute方法不会做任何处理异常将直接传递给线程的异常处理器默认情况下这将导致线程终止并打印堆栈跟踪submit方法会将异常封装在返回的Future对象中。如果任务在执行过程中抛出了异常调用Future对象的get()方法将会抛出ExecutionException该异常会包含原始的异常 10.3 任务类型 execute方法只能接受Runnable类型的任务submit方法除了可以接受Runnable类型的任务外还可以接受Callable类型的任务。Callable与Runnable类似但它可以返回一个结果并且可以抛出异常 10.4 使用场景 当你不需要知道任务执行的结果也不关心任务执行过程中可能发生的异常时可以使用execute方法当你需要跟踪任务的执行状态、结果或者需要在任务完成后进行一些操作如清理资源、处理结果等或者任务可能会抛出异常并且需要捕获处理时应该使用submit方法 总的来说submit 方法提供了比 execute 方法更丰富的功能特别是在方法的返回值和异常处理方面
http://www.tj-hxxt.cn/news/140350.html

相关文章:

  • 苏州网站建站推广网站开发的整体职业规划
  • 宁波网站建设流程wordpress 4.0 4.6
  • 长沙网站制作公司报价php网站是什么数据库文件
  • 有限公司网站入口网站登录页面模板
  • 江西锐安建设工程有限公司网站重庆没建网站的企业
  • 做购物网站怎么写开题报告专业团队值得信赖
  • 招聘织梦网站网站开发原型模板
  • 先注册域名后建设网站可以吗kxsw wordpress
  • 网站数据不变重新安装wordpressseo的目的是什么
  • 临沂专业网站建设公司哪家好网站建设与管理怎么做
  • 自助建站系统搭建网站域名是什么?
  • 深圳高端网站定制公司工作微信管理系统
  • wordpress表单提交邮件通知厦门seo结算
  • 沈阳网站建设首选龙兴科技网站开发和ui的区别
  • 手机网站底部电话柳市做网站的公司
  • 荥阳市城乡建设规划网站网络营销外包顾问
  • 免费网站开发住建部城乡建设网站
  • 湖北建设厅行政服务中心网站苏州高端网站建设机构
  • 建筑模板种类连云港seo公司
  • 贵州建设厅网站办事大厅手机软件app制作工具
  • 包头市建设厅官方网站园林景观设计公司成都
  • 做网站网站犯法吗具权威的小企业网站建设
  • 平台型网站建设个人接广告的平台
  • 做电脑网站用什么软件好用网站做竞价经常会被攻击吗
  • 贵阳市建设厅官方网站域名解析错误无法上网
  • 网站快速备案安全yoast wordpress seo plugin
  • 重庆网站建站价格网站超级链接怎么做
  • 100元网站建设可不可以用帝国cms做企业网站
  • 网站整体设计风格wordpress 8小时前
  • 廊坊网站建设制作最好旅游网站建设