Loading... ## 线程篇 **线程作用:** 提高系统性能,提高响应时间 ### 线程状态 **NEW:** 新建状态,线程被创建出来,但尚未启动时的线程状态; **RUNNABLE:** 就绪状态,表示可以运行的线程状态,它可能正在运行,或者是在排队等待操作系统给它分配 CPU 资源; **BLOCKED:** 阻塞等待锁的线程状态,表示处于阻塞状态的线程正在等待监视器锁,比如等待执行 synchronized 代码块或者使用 synchronized 标记的方法; **WAITING:** 等待状态,一个处于等待状态的线程正在等待另一个线程执行某个特定的动作,比如,一个线程调用了 Object.wait() 方法,那它就在等待另一个线程调用 Object.notify() 或 Object.notifyAll() 方法; **TIMED_WAITING:** 计时等待状态,和等待状态(WAITING)类似,它只是多了超时时间,比如调用了有超时时间设置的方法 Object.wait(long timeout) 和 Thread.join(long timeout) 等这些方法时,它才会进入此状态; **TERMINATED:** 终止状态,表示线程已经执行完成 ### 线程工作模式 线程的工作模式是,首先先要创建线程并指定线程需要执行的业务方法,然后再调用线程的 start() 方法,此时线程就从 NEW(新建)状态变成了 RUNNABLE(就绪)状态,此时线程会判断要执行的方法中有没有 synchronized 同步代码块,如果有并且其他线程也在使用此锁,那么线程就会变为 BLOCKED(阻塞等待)状态,当其他线程使用完此锁之后,线程会继续执行剩余的方法。 当遇到 Object.wait() 或 Thread.join() 方法时,线程会变为 WAITING(等待状态)状态,如果是带了超时时间的等待方法,那么线程会进入 TIMED_WAITING(计时等待)状态,当有其他线程执行了 notify() 或 notifyAll() 方法之后,线程被唤醒继续执行剩余的业务方法,直到方法执行完成为止,此时整个线程的流程就执行完了,执行流程如下图所示: ![线程工作模式](https://image.juinjonn.com:8888/local/2023/01/13/63c10f425235b.png) ### 代码实例 ```java Thread t1 = new Thread(new Runnable() { @Override public void run() { try { System.out.println("Thread --- 1"); TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } } }); // t1.join(); t1.start(); ``` ## 线程池 #### new线程弊端 1. 每次new Thread新建对象性能差。 2. 线程缺乏统一管理,可能无限制新建线程,相互之间竞争,及可能占用过多系统资源导致死机或oom。 3. 缺乏更多功能,如定时执行、定期执行、线程中断。 #### 线程池优点 1. 重用存在的线程,减少对象创建、消亡的开销,性能佳。 2. 可有效控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞。 3. 提供定时执行、定期执行、单线程、并发数控制等功能。 ##### 新建线程池 ```java ExecutorService threadPoolExecutor = new ThreadPoolExecutor(4, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(300)); ``` ###### 参数介绍 **corePoolSize:** 核心线程数 **maximumPoolSize:** 最大线程数 **keepAliveTime:** 线程存活时间 **unit:** 存活时间单位 **workQueue:** 线程队列 **threadFactory:** 线程工厂 **rejectedExecutionHandler:** reject策略 ##### 线程池队列介绍 当线程池收到任务时,会首先启用核心线程,当核心线程饱和时,会将待执行的任务放入到队列中,当线程池队列满时,线程池会执行reject策略。 #### 四种线程池介绍 ##### newCachedThreadPool 创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。 线程池为无限大,当执行第二个任务时第一个任务已经完成,会复用执行第一个任务的线程,而不用每次新建线程。 ```java ExecutorService cachedThreadPool = Executors.newCachedThreadPool(); ``` ##### newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。 ```java ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3); ``` ##### newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行 ```java ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5); scheduledThreadPool.schedule(new Runnable() { @Override public void run() { System.out.println("delay 3 seconds"); } }, 3, TimeUnit.SECONDS); ``` schedule:指定时间后只执行一次 scheduleAtFixedRate:以固定频率来执行某项任务 scheduleWithFixedDelay:执行某项任务,当任务执行完后,延迟固定时间后,在去执行这项任务 ## JDK8并发编程 ### CompletableFuture CompletableFuture实现了CompletionStage接口和Future接口,前者是对后者的一个扩展,增加了异步回调、流式处理、多个Future组合处理的能力,使Java在处理多任务的协同工作时更加顺畅便利 #### 基础使用 ```java CompletableFuture<String> future = CompletableFuture.supplyAsync(()->{ return "hello world"; }); System.out.println(future.get()); //阻塞的获取结果 ''helllo world" ``` #### get 获取结果 ```java //同步获取结果 public T get() public T get(long timeout, TimeUnit unit) public T getNow(T valueIfAbsent) public T join() ``` **getNow** 有点特殊,如果结果已经计算完则返回结果或者抛出异常,否则返回给定的valueIfAbsent值。 **join()** 与**get()** 区别在于**join()** 返回计算的结果或者抛出一个unchecked异常(CompletionException),而**get()** 返回一个具体的异常 **get()** 可以指定超时时间 #### whenComplete ```java public CompletableFuture<T> whenComplete(BiConsumer<? super T,? super Throwable> action) public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T,? super Throwable> action) public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T,? super Throwable> action, Executor executor) public CompletableFuture<T> exceptionally(Function<Throwable,? extends T> fn) ``` 上面4个方法是当计算阶段结束的时候触发,**BiConsumer**有两个入参,分别代表计算返回值,另外一个是异常.无返回值.方法不以Async结尾,意味着Action使用相同的线程执行,而Async可能会使用其它的线程去执行(如果使用相同的线程池,也可能会被同一个线程选中执行)。 **示例** ```java CompletableFuture<String> future = CompletableFuture.supplyAsync(()->{ return "hello world"; }); future.whenCompleteAsync((v,e)->{ System.out.println("return value:"+v+" exception:"+e); }); ``` #### thenApply 当计算结算完成之后,后面可以接继续一系列的thenApply,来完成值的转化 ```java public <U> CompletableFuture<U> thenApply(Function<? super T,? extends U> fn) public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn) public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn, Executor executor) ``` **示例** ```java CompletableFuture<String> future = CompletableFuture.supplyAsync(()->{ return "hello world"; }); CompletableFuture<String> future3 = future.thenApply((element)->{ return element+" addPart"; }).thenApply((element)->{ return element+" addTwoPart"; }); System.out.println(future3.get());//hello world addPart addTwoPart ``` #### thenAccept 只对CompletableFuture的结果进行消费,无返回值,也就是最后的CompletableFuture是void ```java public CompletableFuture<Void> thenAccept(Consumer<? super T> action) public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action) public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action, Executor executor) ``` **示例** ```java CompletableFuture future4 = future.thenAccept((e)->{ System.out.println("without return value"); }); future4.join(); ``` #### thenAcceptBoth 这个方法用来组合两个CompletableFuture,其中一个CompletableFuture等待另一个CompletableFuture的结果. ```java CompletableFuture<String> future = CompletableFuture.supplyAsync(()->{ return "hello world"; }); CompletableFuture future5 = future.thenAcceptBoth(CompletableFuture.completedFuture("compose"), (x, y) -> System.out.println(x+y));//hello world compose ``` 最后修改:2023 年 01 月 13 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 0 如果觉得我的文章对你有用,请随意赞赏