Synchronized
*线程是一个单独的资源类,没有任何负数的操作
new Thread(new MyThread()).star();//不建议这样写
实际开发中要降低耦合 OOP
public void synchronized sale(){};//代码块 排队+锁
lock接口
ReentrantLock可重入锁(常用)
ReadLock读锁
WriteLock写锁
*Lock是一个接口有三个实现类↑
公平锁与非公平锁 先来后到与插队(CPU/默认)
区别
- Syn内置的Java关键字,Lock是一个Java类
- Syn无法判断锁的状态,Lock可以判断是否获取到了锁
- Syn会自动释放,lock必须手动释放 死锁
- Syn线程1获得锁,阻塞,线程2等待 lock不会等 lock.tryLock();尝试获取锁
- Syn 可重入锁,不可以中断 非公平;lock,可重入锁 可以判断 非公平(可以自己设置
- Syn适合少量代码 Lock灵活度很高 适合锁大量的同步代码
锁是什么?如何判断
8锁现象!!对象,class
举例:发短信、打电话
phone才是锁的持有者,先拿到的锁,所以就是先发信息
*新增一个普通方法hello 先hello
*两个对象 两个线程,对象调用的方法都加了锁 没有延迟(打电话)的先输出
*两个静态加锁syn同步方法 只有一个对象 静态方法:类加载就有了。锁的是Class 。phone3.class。class全局唯一。
*两个静态加锁syn同步方法 两个对象 两个线程,对象调用的方法都加了锁 没有延迟的先输出× 先输出发短信 锁的是全局唯一的class
*一个静态同步 一个普通同步加锁 一个对象:前者锁类模板 后者锁调用者。后者不用等前者。所以先打电话。
生产者和消费者问题
/**
*线程之间通信问题 生产者和消费者问题 等待唤醒,通知
*唤醒
*/
//等待→业务→通知
//notify wait
*问题:两个线程 A与B C D 四个线程
//if 判断==》while循环 虚假唤醒
JUC版的生产者和消费者问题
condition里面的东西
wait–>await notify–>signal

Condition实现精准通知
多个监视器实现精准通知
condition1.signal();//唤醒当前signal1
//1执行完要唤醒2
condition2.sinal();
业务->判断->执行->通知
集合类不安全*面试高频
arraylist是不安全的
因为平时在单线程,所以安全
并发修改异常
//java.util.ConcurrentModificationException
/**
*解决方案
*/
List<String> list=new Vector<>();//不好 源码是在add方//法加synchronized
List<String> list=Collections.synchronizedList(new ArrayList<>());
List<String> list=new CopyOnWriteArrayList<>();//源码 //用的是lock锁
3.底层 CopyOnWrite写入时复制 COW计算机程序设置领域的优化策略 多个线程调用的时候,固定的,写入(覆盖)在写入的时候避免覆盖 造成数据问题!

使用Collections.synchronizedList(new ArrayList<>())会比CopyOnWirte快十倍???为什么
set不安全
*blockingQueue与LIst和set同级
CopyOnWriteArraySet 如果用普通的hashSet会报错
Set<String> set=Collections.synchronizedSet(new HashSet<>());
Set<String> set=new CopyOnWriteArraySet<>();
*HashSet底层是什么 其实就是HashMap–>Java基础 红黑树 链表数组
IO类 集合类 常用类 ???
ConcurrentHashMap Map
三个重载 加载因子0.75,初始容量,***重点 桶
Map<String,String> map=new HashMap<>();
//等价于
new HashMap<>(16,0.75);
//解决1.Collections.synchronizedMap();
//解决2.ConcurrentHashMap
//源码!!!!!*****??????
Callable
多线程的第三章创建方式 可以有返回值 可以抛出异常 方法不同run/call()
代码测试
*源码 泛型的参数等于源码的返回值
FutureTask<V>适配类
注意细节:

new Thread(futureTask,"B").start();//结果会被
//缓存,效率高
Integer o=(Integer)futureTask.get();//结果需要等待
Aystem.println.out(o);
get方法可能会阻塞,等待结果,耗时//或者使用异步通信Ajax
三大常用辅助类 (必会)
CountDownLatch计数器
down减法计数器 倒计时完毕会执行某个操作
CountDownLatch countDownLatch=new CountDownLatch(6);
for(int i=0;i<6;i++){
//多线程
countDownLatch.cutdown();//-1
}
countDownLatch.await();//等待归零
//关门
//必须要执行完的任务时才使用
原理:两个方法 减一个等待计数器归零。每次有线程
CyclicBarrierDemo
*问题:lambda里面拿不到i 用final临时变量
Semaphore
一个计数信号量,在
例子抢车位
原理:
release();//释放 会将当前的信号量释放+1 然后唤醒等待的线程
acquire();//得到 如果已经满了,就等待被释放为止-1
多个共享资源互斥的使用!并发限流!
读写锁
都可以被多个线程同时读,写的时候只能有一个线程(不能被插入)去写
加锁版本的读写缓存MyCache 更加细粒度的锁ReentrantReadWriteLock();//不是普通的锁,更加细粒度的控制
private ReadWriteLock readWriteLock=new ReentrantReadWriteLock();
readWriteLock.writeLock().lock();//写,只希望同时只有
//一个线程在写
阻塞队列BlockingQueue
FIFO 先进先出
写入:队列满 必须阻塞等待 取:如果空 必须阻塞等待生产
List–>linkedList/arrayList
blockingQueue–>linkedblockingQueue/arrayblockingQueue

学会使用:blockingQueue 添加/移除
*共计四组API 重要
方式 | 抛出异常 | 有返回值不抛异常 | 一直阻塞 | 等待超时 |
添加 | add | offer(value) | put() | offer(value,timeout,timeunit) |
移除 | remove | poll | take() | poll(timeout,timeunit) |
检测队首元素 | element | peek |
SynchronousQueue同步队列
没有容量 不用设置大小 进去一个元素必须等待取出来才能再放进去一个元素
*消息队列
线程池(重要)
池化技术
本质:占用系统资源,优化资源的使用!==池化技术
线程池、JDBC连接池、内存池、对象池:事先准备好一些资源,有人用,从这里拿走,用完之后还回来,,///创建和销毁十分浪费资源
线程池的好处:
- 降低资源消耗
- 提高效率,提高响应速度
- 方便、统一管理
线程复用,控制最大并发数,管理线程
线程池必会:3大方法*7大参数*4种拒绝策略==》阿里巴巴开发手册
*不允许使用Excutors创建 OOM
import java.util.concurrent.Executors;
//三大方法
ExecutorService threadPool=Executors.new SingleThreadExcutor();
//单一线程 底层是new ThreadPoolExecutor
ExecutorService threadPool=Executors.newFixedThreadPool(5);
//固定大小 底层是new ThreadPoolExecutor
ExecutorService threadPool=Executors.newCachedThreadPool();
//可伸缩的 底层是new ThreadPoolExecutor
threadPool.excute(()->{
```
});
threadPool.shutdown();//关闭线程
*源码本质new ThreadPoolExecutor ==》7个参数
int corePoolSize | 核心线程池大小 |
int maxnumPoolSize | 最大核心线程池大小 |
TimeUnit unit | 超时单位 |
BlockingQueue<Runnable> workQueue | 阻塞队列 |
ThreadFactory threadFactory | 线程工厂 |
long keepAliveTime | 超时了没有人调用就会释放 |
RejecteExcutionHandler hand | 拒绝策略 4种 |
银行业务 :有一天人很多*候客区满了*打开余下窗口
======5个窗口开2个======//core 2 max 5 超时释放(关闭
========候客区=========//阻塞队列
=========拒绝==========//拒绝策略
*4种决绝策略
ExcutorService threadPool =new ThreadPoolExcutor(
2,
5,
3,
TimeUnit.SECONDS,
new linkedBlockingQueue<>(3),
ThreadFactory threadFactory;
new ThreadPoolExcutor.AborPolicy();//拒绝 抛出异常
//new ThreadPoolExcutor.CallerRunsPolicy();//拒绝
)

*最大线程如何定义(调优)
CPU密集型 几核就定义为几 CPU效率最高
Runtime.getRuntime().availableProcessors();
IO密集型 程序 大型任务 占资源 15个任务 判断十分耗IO的线程
四大函数式接口(重要)
lambda表达式、函数式编程、链式编程、Stream流式计算
函数式接口:runnable接口 很多 简化编程模型 底层大量应用
//foreach(消费者类的函数式接口 )
function||函数式接口
传入参数T 返回参数R类型
Predicate||断定型接口
输入一个参数
应用:判断字符串是否为空 return str.isEmpty
Consumer||消费型接口
只有输入没有返回值
Consumer<String> consumer=new Consumer<String>(){
@Override
public void accep(String str){
System.out.println(str);
}
}//打印函数
//lambda表达式方式函数
Consumer<String> consumer=(str)->{
System.out.println(str);
};//打印函数
consumer.accep("hfwuefgwue");
Supplier||供给形接口
调用成功后输出
Supplier supplier=()->{
return 1024;
}
consumer.accep(supplier.get());
Stream流式计算
大数据:存储+计算
集合、mysql本质,是存储东西的;计算应该交给流来做
import java.util.stream
//list有5个用户。不同id,name和age;
//过滤
list.stream()
.filter(u->{return u.getId()%2==0;})//函
//数式接口,过滤
.map(u->{return u.getName().toUpperCase();})//映射
.sorted((a,b)->{return a.compareTo(b);})
.limit(1)
.forEach(System.out::println);//链式编程
- 效率高
- 简洁
ForkJoin
提交效率,大数据量下可以提高,任务拆分–>归并–>最终结果
forkjoin特点:工作窃取,偷工贼,双端队列的基础,B从A的下面取
private Long star;
private Long end;
private Long temp=1000L;
public forkJoinDemo(){
if(end-star>temp){
//大数据下分而治之
}else{
//普通的算法
}
}
//forkJoinPool.excute(ForkJoinTask fork)
//compute

*递归思想
*????流式计算
异步回调
future:对将来的某个事件进行建模 理解Ajax

异步任务
JMM
Java内存模型,不存在的东西。是一个概念!约定!
关于JMM的同步约定:
- 线程解锁前:必须把自己的共享变量!立刻!及时刷回!操作的是自己从主存拷贝过来的数据。
- 线程加锁前:必须要把数据读取出来!把最新值到工作内存中。
- 加锁和解锁是同一把锁
线程、工作内存、主内存
Volatile
*无锁的情况下讨论
volition是最小化的同步块,你用syn当然能解决,但是太重了。
加锁当然可以,因为加锁后运行到同步代码块总是会去刷新工作内存,保证是最新的值,但是加锁效率比较差
轻量级的同步机制
–>如果不加lock和synchronized怎么保证原子性操作?(字节码文件像汇编一样
只是一个add();,在字节码文件中有很多步骤
解决这个,num.getAndIncreament();调用的CAS底层本地方法
和操作系统有关。Unsafe很特殊
指令重排:
源代码–>编译器优化重排–>指令并行重排–>内存系统重排–>执行
数据之间的依赖性问题
可能会造成影响:
线程A 重排 | 线程B |
x=a | y=b |
b=1 | a=2 |
Volatile如何禁止指令重排:
内存屏障,CPU指令。
- 保证特定操作的执行顺序
- 可以保证某些变量的内存可见性(利用这些特性可以保证volatile的可见性
*加了内存屏障 ,底层实现原理

- 保证可见性–jmm 可感知
- 不保证原子性
- 禁止指令重排
单例模式
volatile在单例模式里面用得最多(DCL懒汉式
饿汉式单例
保证只有一个对象,一上来就加载,可能会浪费空间
private Hungry(){
}//构造器私有
private final static Hungry HUNGRY=new Hungry();
public static Hungry getInstance(){
return HUNGRY;
}
懒汉式单例
DCL
private LazyMan(){
Sout;//
}
private volatile static LazyMan lazyMan;
public static LazyMan getInstance(){
if(LazyMan==null){
lazyMan=new LazyMan();//原视频这一块用了
//synchronized代码块
/**
*不是原子性操作
*1.分配空间
*2.执行构造方法,初始化对象
*3.把这个对象指向这个空间
*/
}else
return lazyMan;
}
多线程下不安全所以要用volatile
静态内部类
实现单例
单例不安全因为有👇
反射
用反射破坏单例模式,LazyMan.getInstance拿到对象—》

三个锁解决–》

再次破坏->注解第30行代码(原本的期望上唯一的对象) 没有走原来的构造器
解决:红绿灯:非当前类对象 private static boolean qingjiang=false;
再次破坏->破坏这个对象的私有属性
!!!源码中,枚举类型不允许使用单例模式
我们发现没有无参构造而是有参构造,反编译源码参数是一个String一个是int
深入理解CAS
什么是CAS:深入研究底层 操作系统、计算机网络原理
compareAndSet:比较并交换!如果我期望的值达到了就更新否则就不更新
unsafe java无法操作内存,Java可以调用c++,c++可以操作内存 Java的后门,可以通过这个类操作
底层是自旋锁。CAS:比较当前工作中的值和主存中的值,如果这个值是期望的,那么执行操作!如果不是就一直循环。
缺点:
- 循环会耗时
- 一次性只能保证一个共享变量的原子性
- ABA问题(A、B是线程
ABA问题 狸猫换太子
原子应用 ABA问题
活得版本号 乐观锁
解决ABA问题 引入原子引用 思想:乐观锁
Integer坑🕳
各种锁
公平锁与非公平锁 见上文
公平锁:必须先来后到
非公平锁:可以插队
可重入锁–递归锁
拿到了外面的锁之后,就可以拿到里面的锁,自动的
有一种包含关系,里面的锁执行完外面的锁也才会释放
自旋锁
do while cas 不断尝试直到成功为止 自定义锁测试
死锁
如何分析:死锁是什么,两个人抢夺资源都不放 见上文
如何排查 JPS-l定位进程号、使用jstack-进程号 找到死锁问题
日志、堆栈
发表回复