先建maven项目,JDK8
学习方式:源码,官方文档
什么的JUC java util concurrent就是这三个包
java.util.concurrent java.util.concurrent.atomic java.util.concurrent.locks
thread只是一个普通的线程类
runnable 没有返回值,效率比callable低,所以更多用callable
线程和进程 ,必须要用一句话总结出自己:进程是资源分配的基本单位,程序获得CPU分配的资源后才能执行。线程是资源调度的管理者。
狂神:进程是一个程序,一个进程包含多个线程,Java默认有两个线程(main, GC)
55533.png" alt=“image-20220324161655533” style=“zoom:67%;” />
Java开启线程的方式:runnable ,thread,callable
但是Java无法真正的开启线程
public Thread(ThreadGroup group, Runnable target, String name,
long stackSize) {
init(group, target, name, stackSize);
}
public synchronized void start(){
group.add();
boolean started = false;
try {
start0();
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
}
}
}
//调用本地方法,所以说明Java没有开启线程的能力,调用底层的C++,Java无法控制硬件
private native void start0();
}
并发和并行的区别
并发:多线程操作同一个资源,单核CPU,进程切换,快速交替
并行:多个人一起走,多核CPU,多个线程可以同时运行,线程池
通过代码查看多核Runtime,输出12个
public static void main(String[] args) {
System.out.println(Runtime.getRuntime().availableProcessors());
}
CPU密集型,IO密集型是什么
并发编程的本质:重复利用CPU资源
回顾多线程 线程有几个状态;我:运行态、阻塞态、并行态、
狂:6个
public enum State {
NEW,
RUNNABLE,
BLOCKED,
WAITING,
TIMED_WAITING,
TERMINATED;
}
wait方法和spleep区别
wait占用问题, 锁的问题
- wait来自Object类, sleep来自thread类(企业不会用,企业用 TimeUnit->归属于JUC的Concurrent)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ipuWfTKn-1648363882191)(C:Users86159AppDataRoamingTyporatypora-user-imagesimage-20220324164322519.png)]
- 锁的释放,wait释放锁,sleep抱着锁睡使用范围不同,wait 必须在同步代码块中 sleep可以在任何地方使用,,,,,是否需要捕获异常;wait会中断异常, sleep要捕获(写代码爆红)
狂神说有人写多线程方式是这样的,我是, 继承runnable方法,重写run,new一个新的线程
线程就是一个单独的资源类,没有任何的附属操作
实现接口就不是OOP了,耦合性极高
public static void main(String[] args){
new Thread;
}
class MyThread implements Runnable{
@Override
public void run(){
}
}
函数式接口, 匿名内部类, JDK1.8后简化为lambda表达式 (方法参数 )->{ 代码}
并发解耦
public static void main(String[] args){
Ticket ticket = new Ticket();
new Thread(()->{ticket.sale();}, "A").start();
new Thread(()->{ticket.sale();}, "B").start();
new Thread(()->{ticket.sale();}, "C").start();
}
多个线程用一个资源会发生争抢的现象。
解决:加Sychronized锁,避免争抢。
lock是接口,有3个实现类,可重入锁,读锁,写锁
公平锁:先来后到,
非公平锁:可以插队,防止饥饿,默认
public ReentrantLock() {
sync = new NonfairSync();
}
如何使用:try业务代码, catch, fanally解锁
Lock三部曲:
- new ReentantLock();代码块加锁 Lock.lock();finally解锁
labmda表达式写锁
Synchronized 和Lock的区别 重要- Synchronized是内置的java关键字, Lock是一个Java类Synchronized无法判断获取锁的状态, Lock可以判断是否获取到了锁Synchronized会自动释放锁, Lock手动释放。如果不释放,死锁。Synchronized线程不会争抢,线程1不释放,线程2 就一直等待, Lock不会一直等待。Synchronized可重入锁,不可以中断,非公平, Lock可重入,可判断,默认非公平的,但是可以自己设置。Synchronized适合锁少量的代码同步问题, Lock适合所大量的同步代码。
线程中的通信问题:生产者消费者,线程交替执行操作同一个变量,即通知和等待唤醒
等待,业务逻辑,通知
public static void main(String[] args) {
Data data = new Data();
//不要显示创建线程池,用线程池创建线程
//https://blog.csdn.net/luxing205/article/details/114639313
new Thread(()->{for(int i = 0; i < 10; i++){
try {
data.decrement();
}catch (InterruptedException e){
e.printStackTrace();
}
}
}, "B").start();
}
public class Data{
private int number = 0;
public synchronized void increment(){
//if判断只会判断一次,所以有两个线程进来的时候会发生问题
if (number != 0){
//等待
this.wait();
}
number++;
//通知其他线程
this.notifyAll();
}
public synchronized void decrement(){
if (number == 0){
}
number--;
}
}
面试基本问题:单例模式,排序算法,生产者消费者,死锁 上述代码4个线程还安全吗?
防止虚假唤醒问题,改为while判断
//if判断只会判断一次,所以有两个线程进来的时候会发生问题
while (number != 0){
//等待
this.wait();
}
JUC版的LOCK 生产者消费者问题 Synchronized: wait, notify
Lock: await, signal
通过Lock找到Condition,lock接管了synchronized, condition取代了对象监视器方法的使用
public static class Data{
private int number = 0;
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
public void increment() throws InterruptedException {
lock.lock();
try {
//业务:判断->执行->通知
while (number != 0){
condition.await();
condition.signalAll();
}
number++;
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
任何一个新的技术,绝对不是仅仅覆盖原来的技术,一定有优势。
Condition可以精准的唤醒和通知线程
Condition实现精准的唤醒和通知线程同步监视器:
精准唤醒:
8锁现象 就是关于锁的8个问题学习方法:费曼学习法,学习兴趣,学习态度
什么是锁,锁的是谁锁是new出来的, 而对象是由Class模板new出来
public static void main(String[] args) {
Phone phone = new Phone();
//不是由于先调用,而且先调用不代表先执行,而是锁的作用
new Thread(()->{
phone.sendSms();
},"A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone.call();
},"B").start();
}
public static class Phone{
public synchronized void sendSms(){
System.out.println("sendSms");
}
public synchronized void call(){
System.out.println("call");
}
}
由于这两个方法用的phone这个同一把锁,谁先拿到谁先执行。
加上TimeUnit.SECONDS.sleep(4)延迟和hello方法不加锁可以影响打印顺序
没有锁就不是同步方法,不受锁的影响。
synchronized锁的对象是方法的调用者
public static void main(String[] args) {
Phone phone = new Phone();
//不是由于先调用,而且先调用不代表先执行,而是锁的作用
new Thread(()->{
phone.sendSms();
},"A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone.hello();
},"B").start();
}
static class Phone{
public synchronized void sendSms(){
try {
//是这里的休眠影响了时间,所以在这里要搞清锁的是谁
TimeUnit.SECONDS.sleep(4);
}catch (Exception e){
e.printStackTrace();
}
System.out.println("sendSms");
}
public synchronized void call(){
System.out.println("call");
}
public void hello(){
System.out.println("hello");
}
}
增加两个静态的同步方法
静态方法与普通方法的区别:先执行静态方法(static类一加载就有了) + synchronized
先执行它
public static synchronized void sendSms(){
try {
TimeUnit.SECONDS.sleep(4);
}catch (Exception e){
e.printStackTrace();
}
System.out.println("sendSms");
}
小结:
new this 具体的一个对象
class 具体的模板
Q:既然不占用CPU为什么占用内存,难道是在后台偷偷运行?
读取速度:
CPU -> 内存 -> SSD -> 磁盘 -> 网络 纳秒 -> 微秒 -> 毫秒 -> 毫秒 -> 秒
那哪些软件会主动存到磁盘?为什么选择存在磁盘?
集合类不安全 CopyonWriteArrayList 写入时复制COW计算机程序设计领域的一种优化策略。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vPLsTtXS-1648363882195)(C:Users86159AppDataRoamingTyporatypora-user-imagesimage-20220324224118807.png)]
单线程的代码永远是安全的
List多线程下不安全:
//随机字符串 list.add(UUID.randomUUID().toString().subString(0,5));
如何解决?即并发安全
- List list = new Vector<>(),不好 list并发下不安全Arrays -> Collections.synchronzedList(new ArrayList<>());List list = new CopyOnWriteArrayList<>();
一定要自己动手!
读CopyOnWriteArrayList源码
list.foreach里面有哪些参数,四大函数式接口 CopyonWriteArraySet HashSetBlockingQueue: 阻塞队列
不安全set 初始:又出现ConcurrentModificationException
解决措施:
- 工具类写法:Set set = Collections.synchronizedSet(new HashSet<>());JUC写法:Set set = new CopyOnWriteArraySet<>();
key是无法重复的
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hH0efzx7-1648363882197)(C:Users86159AppDataRoamingTyporatypora-user-imagesimage-20220324225656156.png)]
IO类,集合类,常用类 ConcurrentHashMapHashMap也是不安全的 并发异常
map是这样用的吗,默认等价于什么?
Mapmap = new HashMap<>();
加载因子loadFactor=0.75,初始化容量initialCapacity why???
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Wp5nVtBP-1648363882198)(C:Users86159AppDataRoamingTyporatypora-user-imagesimage-20220324230006824.png)]
看HashMap源码!!!
有问题:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W4xixEhb-1648363882199)(C:Users86159AppDataRoamingTyporatypora-user-imagesimage-20220324231022517.png)]
synchronized
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8d228Kw6-1648363882200)(C:Users86159AppDataRoamingTyporatypora-user-imagesimage-20220324231221044.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8W5Wx2sa-1648363882200)(C:Users86159AppDataRoamingTyporatypora-user-imagesimage-20220324231358310.png)]
解决:
Mapmap = new ConcurrentHashMap<>();
研究ConcurrentHashMap原理!
Callable 可以返回结果和抛出异常,类似于similar@FunctionalInterface public interface cllable{ V call() throws Exception; } public static class MyThread implements Callable { @Override public Integer call() throws Exception { return 1024; } }
不要用runnalbe,因为他没有返回值
implements Callable
//new Thread(new Runnable()).start(); //new Thread(new FutureTask()).start(); //new Thread(new FutureTask (Callable)).start(); 应用: new Thread.start(); MyThread thread = new MyThread(); FutureTask futureTask = new FutureTask(thread); // implements Callable new Thread(futureTask, "A").start(); Integer o = (Integer)futureTask.get();
阿里巴巴规范
分析:
JDK线程池框架继承关系:
线程池构造类ThreadPoolExecutor实现方法
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) { ... ... }
JDK自带的工具类可以创建的线程池种类
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gjLKDfKe-1648363882201)(C:Users86159AppDataRoamingTyporatypora-user-imagesimage-20220325095237983.png)]
引java.util的包 https://juejin.cn/post/6844904074668670984
三大常用辅助类,高并发 CountDownLatch 计数器减法计数器
两个方法:
CountDownLatch.countDown() 数量-1
CountDownLatch.await 等待计数器归零再向下执行, 防止有些数据未操作完
每次有线程调用CountDownLatch()数量-1 ,假设计数器变为0, CountDownLatch.await()就会被唤醒,继续执行。
CyclicBarrier 加法,等待达到数量才会执行[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gwOf4toj-1648363882203)(C:Users86159AppDataRoamingTyporatypora-user-imagesimage-20220325110743674.png)]
<=7代表永远达不到8,就不会开启新的线程
Semaphore ,信号量 并发有个acquire(),假设资源已经满了就等待释放, release方法,信号量释放+1,等待唤醒线程
计数信号量。 从概念上讲,信号量维护一组许可。 如有必要,每个 acquire() 都会阻塞,直到获得许可,然后再接受它。 每个 release() 添加一个许可,可能会释放一个阻塞的获取者。 但是,没有使用实际的许可对象; Semaphore 只是对可用数量进行计数并采取相应措施。
Semaphores are often used to restrict the number of threads than can access some (physical or logical) resource.
抢车位:6个车3个位置,轮流等待车位,用于限流,控制线程最大数,保证高可用。
并发思想大多与操作系统有关
ReadwriteLock 读写锁是ReEntrantLock的更加细粒度ReentrantReadLock读锁独占 reentrantWriteLock 写锁共享,多个线程同时占有
只有一个接口 reentrantlock 都可以被多线程读,写只能被一个线程写
volatile 保证原子性
private vlatile map阻塞队列 队列FIFOmap = new HashMap<>(); map.put写 map.get读
ElasticSearch
不得不阻塞:Input读,队列满了,阻塞等待,队列空了,等待生产,阻塞等待
ArrayBlockingQueue, linkedBlockingQueue
java中的list和set是什么,父:Collection ->Queue -> BlockingQueue,Abstract(非阻塞),Deque ->Array,linked, , 双端队列是一种具有队列和栈性质的抽象数据类型。 双端队列中的元素可以从两端弹出,插入和删除操作限定在队列的两邊进行。
什么情况需要用到阻塞队列:
多线程,线程池的挂起等待,多线程并发处理,线程池
BlockingQueue的四组API- 抛出异常不会抛出异常阻塞等待超时等待
| 方式 | 抛出异常 | 不会抛出异常 | 阻塞等待 | 超时退出 |
|---|---|---|---|---|
| 添加 | add | offer | put | offer(timeout) |
| 移除 | remove | poll空参 | take | poll(timeout) |
| 检测队首元素 | element | peek |
//队列的大小一定要写 ArrayBlockingQueue b = new ArrayBlockingQueue<>(3);
2.不抛出异常,返回布尔值
隶属于BlockingQueue,不存储元素,没有容量,必须等待取出后才能放,即容量为1
new两个线程,一个负责
线程池 三大方法、七大参数、4种拒绝策略 池化技术 事先准备好一些资源,有需要就给程序的运行本质就是利用系统资源去完成任务,所以需要优化CPU资源的实验
线程池、JDBC连接池、内存池、对象池 需要设置核心参数
线程池的好处:降低资源的消耗、提高响应速度、方便管理
即 线程复用、控制最大并发数、管理线程
Executors
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-I8JFfJ5g-1648363882203)(C:Users86159AppDataRoamingTyporatypora-user-imagesimage-20220325171243391.png)]
三大方法:Single:单一线程, Fixed:固定的数量,Cached:容量可伸缩 七大参数 public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,//超时释放
TimeUnit unit, //超时单位
BlockingQueue workQueue,//阻塞队列
ThreadFactory threadFactory,//线程工厂,创建线程,一般不用动
RejectedExecutionHandler handler//拒绝策略) {
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
阿里巴巴规范
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hruPWlcK-1648363882204)(C:Users86159AppDataRoamingTyporatypora-user-imagesimage-20220325173322451.png)]
手动创建线程池[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Hvviqhgm-1648363882204)(C:Users86159AppDataRoamingTyporatypora-user-imagesimage-20220325175547980.png)]
DiscardOldestPolicy队列满了,尝试去和最早的竞争,不会抛出异常
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LwyIk8lG-1648363882205)(C:Users86159AppDataRoamingTyporatypora-user-imagesimage-20220325181458914.png)]
CPU密集型和IO密集型[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-te2Pk8DV-1648363882205)(C:Users86159AppDataRoamingTyporatypora-user-imagesimage-20220325204358011.png)]
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.tonanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}阿里巴巴规范 [外链图片转存中...(img-hruPWlcK-1648363882204)] ##### 手动创建线程池 [外链图片转存中...(img-Hvviqhgm-1648363882204)] ==DiscardOldestPolicy队列满了,尝试去和最早的竞争,不会抛出异常== [外链图片转存中...(img-LwyIk8lG-1648363882205)] #### CPU密集型和IO密集型 [外链图片转存中...(img-te2Pk8DV-1648363882205)]



