juc并发编程
方法引用:
引用符号::三种引用方式
对象名已经存在,成员方法已经存在,则可以使用对象名来引用成员方法类名已经存在,
静态成员方法已经存在,则可以使用类名来引用静态成员方法
构造器引用
一个进程包含多个线程,至少包含一个
java默认 的线程是两个,一个main线程一个gc线程
线程 :
java不能开启线程,开启线程调用的本地的方法 notive调用底层C++
并发编程的本质:充分利用cpu资源
并发/并行
并发(多线程操作同一个资源)
单核CPU,模拟出来多条线程,快速交替
并行(多个人一起行走 )
多核CPU,多个线程一起执行,线程池
线程有六个状态
new新生
runnable运行
blocked阻塞
waiting等待死死的等
time_waiting超时等待
terminated终止
lock锁 实现类ReentrantLock可重入锁
公平锁 先来后到
非公平锁(默认)可以插队
synchronized和lock的区别
synchronized是关键字 lock是一个类
synchronized是自动的无法获取锁的状态 lock可以判断是否获取到了锁
synchronized自动释放锁 lock需要手动释放锁 不然会死锁
synchronized两个线程如果A得到锁B会等待,A阻塞B会一直等待 lock就不一定因为有 trylock方法
synchronized可重入锁,不可以中断,非公平 lock可重入锁,可以判断锁,非公平和公平
synchronized适合锁少量的 代码同步问题 lock适合大量的同步代码
synchronized生产者消费者如果用if判断会有虚假唤醒问题,需要用while
lock的wait和notify
condition(相当于监视器)可以多几个来signal精准的通知和唤醒线程 await signal
8锁现象
synchronized锁的对象是方法的调用者 ,是谁先拿到 谁先执行 详情见D:\Develop\apache-maven-3.8.6-bin\repository\juc的Demo8_1
有一个普通方法和两个调用对象的时候详见Demo8_2
加上static锁的是类详见Demo8_3
一个静态同步方法锁,一个普通锁详见Demo8_4
lock有一个newCondition,唤醒对应的线程
集合类不安全:
list不安全
1.vector直接就是安全的集合synchronized的效率慢 这个类比list出的都早
2.collections.synchronizedlist(除了list还有好多)
3.juc包里有很多比如CopyOnWriteArrayList等等
set和list一样不过没有vector
set底层就是,map的key 所以是不能重复的 add方法就是调用put方法
Map
加载因子,初始化容量
并发的map可以用 ConcurrentHasMap
Callable
可以有返回值
可以抛出异常
方法不同 call();
线程调用方法 new thread().start()
由于thread里面需要传一个runnable 但是 callable不对,所以需要一个适配器 futureTask 把callable传进去。然后放到thread里面
获取返回值有一个get方法,但是有可能会阻塞,所以把它写到最后一行 或者异步通信
还有就是两个线程调用一个,会有缓存,只执行一遍
CountDownLatch 减法计数器
.countDown减一
.await 等待归零 在进行下面你的操作
CyclicBarrier 加法计数器
.await 够了之后 在进行下面你的操作
Semaphore线程阻塞设置几个 几个可以先走
acquire()获取
ReadWriteLock读写锁/共享锁(读锁)/独占锁(写锁)
实现类ReentrantReadWriteLock
readWriteLock.writeLock().lock();
1 try{}catch{}
finally{readWriteLock.writeLock().unlock();}
阻塞队列blockingQueue 非阻塞队列AbstractQueue 双端队列 Deque
队列:FIFO 先进先出 写入: 队列满了 就需要阻塞等待 取:队列是空的话必须阻塞等待生产
多线程并发,线程池 常用
方式 | 抛出异常 | 不会抛出异常有返回值 | 阻塞等待 | 超时等待 |
添加 |
add |
offer() | put | offer(参数,时间,timeunit) |
移除 | remove | poll() | take | poll(时间,timeunit) |
判断队列首部 |
element
|
peek() |
synchronizedQueue同步队列 put take
线程池(重点)三大方法、七大参数、四种拒绝策略
最好不用Executors而是用ThreadPoolExecutor
好处:降低资源的消耗,提高响应的速度,方便管理 ------>线程复用,可以控制最大并发数,管理线程
线程池需要用线程池启动线程 .execute 线程池需要关闭的 .shutdown 放在finally里面
三大方法:
newSingleThreadExecutor 创建单一的线程
newFixedThreadPool() 规定线程个数
newCachedThreadPool 缓存线程 遇强则强
七大参数:最大承载线程,队列加最大核心线程
ThreadPoolExecutor(核心线程大小,最大核心线程大小(cpu密集型(根据电脑来),IO密集型(大于你程序中耗IO的线程)),
超时了没有人调用就会释放,超时单位,阻塞队列,线程工厂创建线程,拒绝策略)
四种拒绝策略
AbortPolicy超过最大承载就会抛出异常
CallerRunsPolicy哪来的去哪里,调用线程的人去执行
DiscardPolicy队列满了不会抛出异常,丢弃任务
DiscardOldestPolicy尝试和最早的竞争,抛弃最早的进去队列
四大函数式接口:只有一个抽象方法 ,比如runnable
@FunctionInterface
function 函数式接口传入T返回R
Predicate 断定型接口有一个输入参数返回值是布尔类型
consumer 消费型接口 只要输入没有返回值
supplier 供给型接口 只有返回值 没有输入
Stream流式计算
一直.下去 链式编程
ForkJoin
JDK1.7之后出来,并行执行任务时提高效率,大数据量
特点:工作窃取 比如两个线程一个执行完了他会偷取另外一个线程的任务,不让线程等待 都是双端队列
想要用的话,需要继承 RecursiveTask<>继承之后就是计算任务,然后fork()方法拆分任务,把任务压入线程队列task1.join+task2.join join方法
需要用线程池去提交任务 newforkJoinPool 然后.submit或者execute submit.get获取结果
详见DemoForkJoin.java
异步回调:future有任务需要一定的时间才能执行完,我们不需要等,可以先去执行其他任务,需要结果的时候再拿过来
实现类用CompletableFuture<Void>这是没有返回值的 CompletableFuture.runAsync (上下都是函数式接口用lambda) .get获取结果
CompletableFuture.supplyAsync
详见DemoFuture
JMM:java内存模型,不存在的东西,概念 约定
volatile是Java虚拟机提供的轻量级的同步机制
特点:
1.保证可见性
2.不保证原子性
3.禁止指令重排
约定
1.线程解锁前,必须把共享变量立刻刷会主存
2.线程加锁前,必须读取主存中的最新值到工作内存中
3.加锁和解锁是同一把锁
原子性:Atomic
指令重排,计算机执行程序 源代码-->编译器优化代码重排-->指令并行也可能会重拍-->内存系统也会重拍-->执行
内存屏障在单利模式中使用的最多
单例模式,构造器私有 详见D:\Develop\apache-maven-3.8.6-bin\repository\juc\src\main\java\com\songyue\juc
下的DemoSingle
饿汉式:
DCL懒汉式:双重检测锁模式
枚举 enum本身是一个类 class-->enum 枚举类型没有无参构造,有一个两个参数的构造方法(string,int)
CAS(自带原子性):ABA问题(你拿到的值其实已经被其他线程修改过了)
比较当前内存中的值和期望的值,如果这个值是期望的那么久执行操作,否则一直循环
一次性只能保存一个变量的原子性
AtomicReference原子引用(初始值,版本号).getStamp获取版本号 解决ABA问题
unsafe类
各种锁的理解
公平锁:非常公平不能插队
非公平锁:可以插队
可重入锁:一个锁进入另一个锁
自旋锁:spinlock详见MyDemoSpinlock
死锁:
怎么排查死锁:jps -L(小写)定位进程号 jstack 进程号
日常排查问题:可以看日志 可以看堆栈信息
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现