JUC介绍--狂神视频笔记

先建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) {
                /* do nothing. If start0 threw a Throwable then
                  it will be passed up the call stack */
            }
        }
    }
//调用本地方法,所以说明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 {
        /**线程新生
         * Thread state for a thread which has not yet started.
         */
        NEW,
        /**运行
         *A thread in the runnable state is executing in the Java virtual machine but it maybe waiting for other resources from the operating system such as processor.
         */
        RUNNABLE,
        /**
         * A thread in the blocked state is waiting for a monitor lock to enter a synchronized block/method or
         */
        BLOCKED,
        /**死死的等
         * Thread state for a waiting thread.
         * A thread is in the waiting state due to calling one of the following methods:
         * is waiting for a specified thread to terminate.
         */
        WAITING,
        /** 超时等待,过期不候
         * Thread state for a waiting thread with a specified waiting time.
         * A thread is in the timed waiting state due to calling one of the following methods with a specified positive waiting time:
         */
        TIMED_WAITING,
        /** 终止
         * The thread has completed execution.
         */
        TERMINATED;
    }
wait方法和spleep区别

wait占用问题, 锁的问题

  1. wait来自Object类, sleep来自thread类(企业不会用,企业用 TimeUnit->归属于JUC的Concurrent)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ipuWfTKn-1648363882191)(C:\Users\86159\AppData\Roaming\Typora\typora-user-images\image-20220324164322519.png)]

  1. 锁的释放,wait释放锁,sleep抱着锁睡
  2. 使用范围不同,wait 必须在同步代码块中 sleep可以在任何地方使用,,,,,
  3. 是否需要捕获异常;wait会中断异常, sleep要捕获(写代码爆红)

Lock锁

Synchronized锁

狂神说有人写多线程方式是这样的,我是, 继承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三部曲:

  1. new ReentantLock();
  2. 代码块加锁 Lock.lock();
  3. finally解锁

labmda表达式写锁

Synchronized 和Lock的区别 重要

  1. Synchronized是内置的java关键字, Lock是一个Java类
  2. Synchronized无法判断获取锁的状态, Lock可以判断是否获取到了锁
  3. Synchronized会自动释放锁, Lock手动释放。如果不释放,死锁。
  4. Synchronized线程不会争抢,线程1不释放,线程2 就一直等待, Lock不会一直等待。
  5. Synchronized可重入锁,不可以中断,非公平, Lock可重入,可判断,默认非公平的,但是可以自己设置。
  6. Synchronized适合锁少量的代码同步问题, Lock适合所大量的同步代码。
所以锁是什么,如何判断锁的是谁?

传统的生产者消费者问题,防止虚假唤醒

Synchronized 的 wait notify版本
  1. 线程中的通信问题:生产者消费者,线程交替执行操作同一个变量,即通知和等待唤醒

    等待,业务逻辑,通知

      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实现精准的唤醒和通知线程

同步监视器:

image-20220324202303249

精准唤醒:

image-20220324202718071

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:\Users\86159\AppData\Roaming\Typora\typora-user-images\image-20220324224118807.png)]

单线程的代码永远是安全的

List多线程下不安全:

//随机字符串
list.add(UUID.randomUUID().toString().subString(0,5));

如何解决?即并发安全

  1. List list = new Vector<>(),不好 list并发下不安全
  2. Arrays -> Collections.synchronzedList(new ArrayList<>());
  3. List list = new CopyOnWriteArrayList<>();

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yLomD4Ng-1648363882196)(C:\Users\86159\AppData\Roaming\Typora\typora-user-images\image-20220324223844580.png)]

一定要自己动手!

读CopyOnWriteArrayList源码

list.foreach里面有哪些参数,四大函数式接口
CopyOnWriteArraySet HashSet

BlockingQueue: 阻塞队列

不安全set 初始:又出现ConcurrentModificationException

image-20220324225212955

解决措施:

  1. 工具类写法:Set set = Collections.synchronizedSet(new HashSet<>());
  2. JUC写法:Set set = new CopyOnWriteArraySet<>();
HashSet的底层:就是hashmap

key是无法重复的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hH0efzx7-1648363882197)(C:\Users\86159\AppData\Roaming\Typora\typora-user-images\image-20220324225656156.png)]

IO类,集合类,常用类
ConcurrentHashMap

HashMap也是不安全的 并发异常

map是这样用的吗,默认等价于什么?

Map<String, String> map = new HashMap<>();

加载因子loadFactor=0.75,初始化容量initialCapacity why???

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Wp5nVtBP-1648363882198)(C:\Users\86159\AppData\Roaming\Typora\typora-user-images\image-20220324230006824.png)]

看HashMap源码!!!

有问题:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W4xixEhb-1648363882199)(C:\Users\86159\AppData\Roaming\Typora\typora-user-images\image-20220324231022517.png)]

synchronized

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8d228Kw6-1648363882200)(C:\Users\86159\AppData\Roaming\Typora\typora-user-images\image-20220324231221044.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8W5Wx2sa-1648363882200)(C:\Users\86159\AppData\Roaming\Typora\typora-user-images\image-20220324231358310.png)]

解决:

Map<String, String> map = new ConcurrentHashMap<>();

研究ConcurrentHashMap原理!

Callable 可以返回结果和抛出异常,类似于similar
@FunctionalInterface
public interface cllable<V>{
    V call() throws Exception;
}
    public static class MyThread implements Callable<Integer>{
        @Override
        public Integer call() throws Exception {
            return 1024;
        }
    }

不要用runnalbe,因为他没有返回值

implements Callable

//new Thread(new Runnable()).start();
//new Thread(new FutureTask<V>()).start();
//new Thread(new FutureTask<V>(Callable)).start();
应用:
    new Thread.start();
	MyThread thread = new MyThread();
	FutureTask futureTask = new FutureTask(thread); // implements Callable<V>
	new Thread(futureTask, "A").start();
	Integer o = (Integer)futureTask.get();

阿里巴巴规范

image-20220325094630198 image-20220325094711208

分析:

JDK线程池框架继承关系:

image-20220325095039796

线程池构造类ThreadPoolExecutor实现方法

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                     	  RejectedExecutionHandler handler) { ... ... }

JDK自带的工具类可以创建的线程池种类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gjLKDfKe-1648363882201)(C:\Users\86159\AppData\Roaming\Typora\typora-user-images\image-20220325095237983.png)]

引java.util的包 https://juejin.cn/post/6844904074668670984

三大常用辅助类,高并发

CountDownLatch 计数器

减法计数器

两个方法:

CountDownLatch.countDown() 数量-1

CountDownLatch.await 等待计数器归零再向下执行, 防止有些数据未操作完

每次有线程调用CountDownLatch()数量-1 ,假设计数器变为0, CountDownLatch.await()就会被唤醒,继续执行。

image-20220325105959982
CyclicBarrier 加法,等待达到数量才会执行

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gwOf4toj-1648363882203)(C:\Users\86159\AppData\Roaming\Typora\typora-user-images\image-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个位置,轮流等待车位,用于限流,控制线程最大数,保证高可用。

并发思想大多与操作系统有关

image-20220325111920318
ReadwriteLock 读写锁是ReEntrantLock的更加细粒度

ReentrantReadLock读锁独占 reentrantWriteLock 写锁共享,多个线程同时占有

image-20220325145227300 image-20220325145146865

只有一个接口 reentrantlock 都可以被多线程读,写只能被一个线程写

volatile 保证原子性

private vlatile map<String, Object> map = new HashMap<>();
map.put写
map.get读
阻塞队列 队列FIFO

ElasticSearch

不得不阻塞:Input读,队列满了,阻塞等待,队列空了,等待生产,阻塞等待

ArrayBlockingQueue, LinkedBlockingQueue

java中的list和set是什么,父:Collection ->Queue -> BlockingQueue,Abstract(非阻塞),Deque ->Array,Linked, , 双端队列是一种具有队列和栈性质的抽象数据类型。 双端队列中的元素可以从两端弹出,插入和删除操作限定在队列的两邊进行。

image-20220325150557451

什么情况需要用到阻塞队列:

多线程,线程池的挂起等待,多线程并发处理,线程池

BlockingQueue的四组API
  1. 抛出异常
  2. 不会抛出异常
  3. 阻塞等待
  4. 超时等待
方式抛出异常不会抛出异常阻塞等待超时退出
添加addofferputoffer(timeout)
移除removepoll空参takepoll(timeout)
检测队首元素elementpeek
//队列的大小一定要写
ArrayBlockingQueue b = new ArrayBlockingQueue<>(3);
image-20220325151114715

2.不抛出异常,返回布尔值

image-20220325151533042
image-20220325151929895
SychronousQueue同步队列

隶属于BlockingQueue不存储元素,没有容量,必须等待取出后才能放,即容量为1

new两个线程,一个负责

image-20220325153203477

线程池 三大方法、七大参数、4种拒绝策略

池化技术 事先准备好一些资源,有需要就给

程序的运行本质就是利用系统资源去完成任务,所以需要优化CPU资源的实验

线程池、JDBC连接池、内存池、对象池 需要设置核心参数

线程池的好处:降低资源的消耗、提高响应速度、方便管理

即 线程复用、控制最大并发数、管理线程

Executors

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-I8JFfJ5g-1648363882203)(C:\Users\86159\AppData\Roaming\Typora\typora-user-images\image-20220325171243391.png)]

三大方法:Single:单一线程, Fixed:固定的数量,Cached:容量可伸缩
七大参数
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,//超时释放
                              TimeUnit unit, //超时单位
                              BlockingQueue<Runnable> 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:\Users\86159\AppData\Roaming\Typora\typora-user-images\image-20220325173322451.png)]

手动创建线程池

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Hvviqhgm-1648363882204)(C:\Users\86159\AppData\Roaming\Typora\typora-user-images\image-20220325175547980.png)]

DiscardOldestPolicy队列满了,尝试去和最早的竞争,不会抛出异常

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LwyIk8lG-1648363882205)(C:\Users\86159\AppData\Roaming\Typora\typora-user-images\image-20220325181458914.png)]

CPU密集型和IO密集型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-te2Pk8DV-1648363882205)(C:\Users\86159\AppData\Roaming\Typora\typora-user-images\image-20220325204358011.png)]

  1.     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)]











































  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值