1.本课程前置知识及要求说明
1.1 JUC是什么
java.util.concurrent 在并发编程中使用的工具包
1.2 本课程学生对象(非零基础)
1.3 本课程的难度对标
1.4 前置知识
1.4.1 IDEA开发工具和常用快捷键自定义配置
1.4.2 IDEA之lombok插件
1.4.3 Java8新特性
Java8语法本身+函数式编程+方法引用+lambda表达式
登陆B站-宋红康Java8新特性视频地址
https://www.bilibili.com/video/BV18J411x7XS/?p=2&spm_id_from=pageDriver&
vd_source=c634d163b940964d44747b4c3976117b
1.4.4 JUC初级篇
1.4.4.1 JUC要求的知识内容
ReentrantLock
ReentrantReadwriteLock
Condition
工具类
CountDownLatch
CyclicBarrier
Semaphore
线程池与阻塞队列
ForkJoinPool与ForkJoinTask
原子操作类Atomic
volatile
Callable和FutureTask
1.4.4.2 登陆B站-JUC并发编程
https://www.bilibili.com/video/BV1Kw411Z7dF/?p=2&spm_id_from=pageDriver&vd_source=c6
34d163b940964d44747b4c3976117b
1.4.5 JVM
1.4.5.1 JVM体系结构概览
1.5 本次讲解采用的Java版本
2. 线程基础知识复习
2.1 1把锁synchronized
2.2 并发,并行
并发(concurrent):进程中的线程是由CPU负责调度执行的,但CPU能同时处理线程的数量有限,
为了保证全部线程都能往前执行CPU会轮询为系统的每个线程服务,由于CPU切换的速度很快,给我们
的感觉这些线程在同时执行,这就是并发。
并行(parallel):在同一个时刻上,同时有多个线程在被CPU调度执行。
2.3 进程,线程,管程
进程:在系统中运行的一个应用程序,每个进程都有它自己的内存空间和系统资源
线程:也被称为轻量级进程,在同一个进程内会有1个或多个线程,是大多数操作系统进行时序调度
的基本单元。
管程:Monitor(锁),也就是我们平时所说的锁。Monitor其实是一种同步机制,它的义务是保证
(同一时间)只有一个线程可以访问被保护的数据和代码,JVM中同步是基于进入和退出监视器
(Monitor管程对象)来实现的,每个对象实例都会有一个Monitor对象,Monitor对象和Java对象一同
创建并销毁,底层由C++语言实现。
2.4 线程分类
1. 用户线程:是系统的工作线程,它会完成这个程序需要完成的业务操作。
2. 守护线程:是一种特殊的线程为其他线程服务的,在后台默默地完成一些系统性的任务,比如
垃圾回收线程就是最典型的例子。守护线程作为一个服务线程,没有服务对象就没有必要继续
运行了,如果用户线程全部结束了,意味着程序需要完成的业务操作已经结束了,系统可以退
出了。所以假如当系统只剩下守护线程的时候,守护线程伴随着JVM一同结束工作。
3. CompletableFuture
3.1 Future接口理论知识复习
Future接口(FutureTask实现类)定义了操作异步任务执行一些方法,如获取异步任务的执行结
果、取消异步任务的执行、判断任务是否被取消、判断任务执行是否完毕等。
/**
* @title
* @description
* @author prefule
* @updateTime 2023/9/8 9:57
* @throws
*/
public class DaemonDemo {
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
System.out.println(Thread.currentThread().getName() + " 开始运行,"
+ (Thread.currentThread().isDaemon() ? "守护线程" : "用户线
程"));
while (true) {
}
}, "t1");
//通过设置属性Daemon来设置当前线程是否为守护线程
t1.setDaemon(true);
t1.start();
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 主线程结束");
}
}
/*
t1 开始运行,守护线程
main 主线程结束
Process finished with exit code 0
*/
举例:比如主线程让一个子线程去执行任务,子线程可能比较耗时,启动子线程开始执行任务后,
主线程就去做其他事情了,忙完其他事情或者先执行完,过了一会再才去获取子任务的执行结果或变更
的任务状态(老师上课时间想喝水,他继续讲课不结束上课这个主线程,让学生去小卖部帮老师买水完
成这个耗时和费力的任务)。
3.2 Future接口常用实现类FutureTask异步任务
3.2.1 Future接口能干什么
Future是Java5新加的一个接口,它提供一种异步并行计算的功能,如果主线程需要执行一个很耗时
的计算任务,我们会就可以通过Future把这个任务放进异步线程中执行,主线程继续处理其他任务或者
先行结束,再通过Future获取计算结果。
3.2.2 Future接口相关架构
目的:异步多线程任务执行且返回有结果,三个特点:多线程、有返回、异步任务(班长为老
师去买水作为新启动的异步多线程任务且买到水有结果返回)
代码实现:Runnable接口+Callable接口+Future接口和FutureTask实现类。
/**
* @title
* @description
* @author prefule
* @updateTime 2023/9/8 9:57
3.2.3 Future编码实战和优缺点分析
优点:Future+线程池异步多线程任务配合,能显著提高程序的运行效率。
缺点:
get()阻塞:一旦调用get()方法求结果,一旦调用不见不散,非要等到结果才会离
开,不管你是否计算完成,如果没有计算完成容易程序堵塞。
isDone()轮询:轮询的方式会耗费无谓的cpu资源,而且也不见得能及时得到计算结
果,如果想要异步获取结果,通常会以轮询的方式去获取结果,尽量不要阻塞。
结论:Future对于结果的获取不是很友好,只能通过阻塞或轮询的方式得到任务的结果。
* @throws
*/
public class CompletableFutureDemo {
public static void main(String[] args) throws ExecutionException,
InterruptedException {
FutureTask<String> futureTask = new FutureTask(new MyThread());
//开启一个异步线程
Thread t1 = new Thread(futureTask);
t1.start();
//有返回hello Callable
System.out.println(futureTask.get());
}
}
class MyThread implements Callable<String> {
@Override
public String call() throws Exception {
System.out.println("--------come in");
return "hello Callable";
}
}
/**
--------come in
hello Callable
Process finished with exit code 0
*/
package com.bilibili.juc.mytest.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
/**
* @title
* @description
* @author prefule
* @updateTime 2023/9/8 9:57
* @throws
*/
public class FutureApiDemo {
public static void main(String[] args) throws ExecutionException,
InterruptedException, TimeoutException {