并发编程尚硅谷笔记

并发编程

网课链接 https://www.bilibili.com/video/BV1Kw411Z7dF?from=search&seid=17866093614757364189&spm_id_from=333.337.0.0

相关笔记链接 https://blog.csdn.net/weixin_47872288/article/details/119453092

代码地址 https://gitee.com/userwhz/juc-ssg

1.JUC概述


java.util.concurrent工具包的简称



进程

线程	程序执行的最小单元





线程的状态

NEW	新建

RUNNABLE	准备就绪

BLOCKED	阻塞

WAITING	不见不散

TIMED_WAITING	过时不候

TERMINATED	终结



wait和sleep的区别

wait是Thread的静态方法,wait是Object的方法,任何对象实例都能调用

sleep不会释放锁,也不需要占用锁,wait会释放锁,但调用它的前提是当前线程占有锁(即代码要在synchronized中)

都可以被interrupted方法中断



并发	不是同一时刻

并行	同一时刻



管程	Monitor(监视器)

保证同一时间,只有一个线程



用户线程	自定义线程



守护线程	比如垃圾回收

没有用户线程,守护线程也会结束

2.Lock接口


synchronizd	同步锁

卖票案例



多线程编程步骤一

创建资源类,创建属性和操作方法

创建多线程调用资源类的方法



创建线程的多种方式

继承Thread类	少用

实现Runnable接口

使用Callable接口

使用线程池



Lock接口	java.util.concurrent.locks

需要手动上锁和释放锁

实现类

ReentrantLock	可重入锁	

可重入就是说某个线程已经获得某个锁,可以再次获取锁而不会出现死锁

卖票案例



Lock和synchronized去呗

Lock是接口,synchronized是关键字,是内置的语言实现

synchronized发生异常时,会自动释放锁,因此不会死锁。Lock发生异常时,没有手动释放锁的话,很容易造成死锁现象


3.线程间通信


多线程编程步骤二

资源类

判断

干活

通知



synchronized实现线程间通信

wait

notifyAll



虚假唤醒问题

循环判断while解决



Lock实现线程间通信

condition

await

signalAll



4.线程间定制化通信

让线程按顺序执行特定次数

通过标志位实现

5.集合的线程安全

Arraylist线程不安全演示

java.util.ConcurrentModificationException

并发修改异常



解决方案

1)Vector

2)Collections

3)CopyOnWriteArraylist

读的时候支持并发读

写的时候独立写



HashSet线程不安全	不重复 无序

CopyOnWriteArraySet



HashMap线程不安全

ConcurrentHashMap


6.多线程锁


synchronized八种锁问题



synchronized在方法名上锁的是对象



static synchronized 锁定的是class



static synchronized 和	synchronized 锁的不一样






公平锁

ReentrantLock lock  = new ReentrantLock (true) 公平锁 

默认false 非公平

非公平锁	

优点	效率高

缺点	造成线程饿死




可重入锁	又叫做递归锁

synchronized	隐式

lock	显式	

都是可重入锁





死锁

死锁出现一定会出现以下四个条件,但是出现以下四个条件不一定死锁

1)互斥: 在一个时间一个资源只能由一个进程使用

2)持有并等待: 进程保持至少一个资源正在等待获取其他进程持有的额外资源

3)无抢占: 一个资源只能被进程资源释放,进程已经完成了它的任务之后

4)循环等待: 存在等待进程集合{P0,P1,...,Pn},P0正在等待P1所占用的资源,P1正在等待P2占用的资源...Pn-1在等待Pn的资源,Pn正在等

待P0所占用的资源

7.Callable接口


创建线程方法

继承Thread类

实现Runnable接口

通过Callable接口	

线程池方式



Runnbale当线程终止时,无法使线程返回结果



Callable接口	和	Runnable

是否有返回值



call	无法计算结果时,抛出异常



Runnable接口有实现类FutureTask


8.JUC的强大辅助类


减少计数	CounutDownLatch	

await	变成0后输出

countDown	-1





循环栅栏	CyclicBarrier

await	





信号灯	Semaphore

acquire

release



9.ReentrantReadWriteLock读写锁


悲观锁	

乐观锁



表锁	整张表上锁

行锁	只对一条记录上锁	可能会发生死锁



读锁	共享锁	可能会发生死锁

写锁	排他锁	可能会发生死锁





readWriteLock.writeLock().lock();

readWriteLock.writeLock().unlock();

readWriteLock.readLock().lock();

readWriteLock.readLock().unlock();



读写锁

一个资源可以被多个读线程访问,或者可以被一个写线程访问,但是不可以同时存在读线程和写线程。

锁饥饿问题,一直读没有写

读的时候不能进行写操作



锁降级

将写入锁降级为读锁

获取写锁	获取读锁	释放写锁	释放读锁

读锁不能升级为写锁

ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();

ReentrantReadWriteLock.ReadLock readLock = reentrantReadWriteLock.readLock();

ReentrantReadWriteLock.WriteLock writeLock = reentrantReadWriteLock.writeLock();


10.BlockingQueue阻塞队列

阻塞队列

不需要关注什么时候唤醒线程,什么时候阻塞线程



分类

1)ArrayBlockingQueue

基于数组的阻塞队列

由数组结构组成的有界阻塞队列



2)LinkedBlockingQueue

基于链表的阻塞队列

由链表结构组成的有界(但大小默认值为integer.MAX_VALUE)阻塞队列



3)DelayQueue
使用优先级队列实现的延迟无界阻塞队列

DelayQueue 中的元素只有当其指定的延迟时间到了,才能够从队列中获取到该元素。DelayQueue 是一个没有大小限制的队列,因此往

队列中插入数据的操作(生产者)永远不会被阻塞,而只有获取数据的操作(消费者)才会被阻塞

4)PriorityBlockingQueue

基于优先级的阻塞队列

支持优先级排序的无界阻塞队列

不会阻塞数据生产者,而只会在没有可消费的数据时,阻塞数据的消费者

5.SynchronousQueue

一种无缓冲的等待队列

相对于有缓冲的 BlockingQueue 来说,少了一个中间经销商的环节(缓冲区)

不存储元素的阻塞队列,也即单个元素的队列

声明一个 SynchronousQueue 有两种不同的方式,它们之间有着不太一样的行为。

公平模式和非公平模式的区别:

• 公平模式:SynchronousQueue 会采用公平锁,并配合一个 FIFO 队列来阻塞

多余的生产者和消费者,从而体系整体的公平策略;

• 非公平模式(SynchronousQueue 默认):SynchronousQueue 采用非公平锁,同时配合一个 LIFO 队列来管理多余的生产者和消费者

而后一种模式,如果生产者和消费者的处理速度有差距,则很容易出现饥渴的情况,即可能有某些生产者或者是消费者的数据永远都得不

到处理

6.LinkedTransferQueue

由链表结构组成的无界阻塞 TransferQueue 队列

由链表组成的无界阻塞队列

预占模式。意思就是消费者线程取元素时,如果队列不为空,则直接取走数据,若队列为空,生成一个节点(节点元素为 null)入队,消

费者线程被等待在这个节点上,生产者线程入队时发现有一个元素为 null 的节点,生产者线程就不入队了,直接就将元素填充到该节

点,并唤醒该节点等待的线程,被唤醒的消费者线程取走元素,从调用的方法返回

7.LinkedBlockingDeque

由链表结构组成的双向阻塞队列

阻塞有两种情况

插入元素时: 如果当前队列已满将会进入阻塞状态,一直等到队列有空的位置时再该元素插入,该操作可以通过设置超时参数,超时后返

回 false 表示操作失败,也可以不设置超时参数一直阻塞,中断后抛出 InterruptedException异常

读取元素时: 如果当前队列为空会阻塞住直到队列不为空然后返回元素,同样可以通过设置超时参数



方法	抛出异常	特殊值	组塞	超时

插入	add 	offer	put	offer

移除	remove	poll	take	poll

检查	element	peek	不可用	不可用



11.ThreadPool线程池


特点

- 降低资源消耗: 通过重复利用已创建的线程降低线程创建和销毁造成的销耗。
- 提高响应速度: 当任务到达时,任务可以不需要等待线程创建就能立即执行。
- 提高线程的可管理性: 线程是稀缺资源,如果无限制的创建,不仅会销耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。





使用方法

Executors.newFixedThreadPool(int)一池N线程

ExecutorService threadPool1 = Executors.newFixedThreadPool(5); //5个窗口

Executors.newSingleThreadExecutor()一池一线程

 ExecutorService threadPool2 = Executors.newSingleThreadExecutor(); //一个窗口

Executors.newCachedThreadPool()一池可扩容根据需求创建线程

ExecutorService threadPool3 = Executors.newCachedThreadPool();



线程池7个参数含义

int corePoolSize	常驻线程数量(核心)

int maximumPoolSize	最大线程数量

long keepAliveTime,TimeUnit unit	线程存活时间	时间单位

BlockingQueue<Runnable> workQueue	阻塞队列(排队的线程放入)

ThreadFactory threadFactory	线程工厂,用于创建线程

RejectedExecutionHandler handler	拒绝测试(线程满了)



拒绝策略

AbortPolicy(默认)	直接抛出RejectedExecutionException异常阻止系统正常运行

callerRunsPolicy 	“调用者运行“—种调节机制,该策略既不会抛弃任务,也不会抛出异常,而是将某些任务回退到调用者,从而降低新任

务的流量。

DiscardOldestPolicy 	抛弃队列中等待最久的任务,然后把当前任务加人队列中尝试再次提交当前任务。

DiscardPolicy 	该策略默默地丢弃无法处理的任务,不予任何处理也不抛出异常。如果允许任务丢失,这是最好的—种策略。



具体工作流程

在执行创建对象的时候不会创建线程

创建线程的时候execute()才会创建

先到常驻线程,满了之后再到阻塞队列进行等待,阻塞队列满了之后,在往外扩容线程,扩容线程不能大于最大线程数。大于最大线程数

和阻塞队列之和后,会执行拒绝策略。


12.Fork/Join分支合并框架


将一个大的任务拆分成多个子任务进行并行处理,最后将子任务结果合并成最后的计算结果

该算法相当于递归,且是二分查找思路



ForkJoinTask:我们要使用 Fork/Join 框架,首先需要创建一个 ForkJoin 任务。该类提供了在任务中执行 fork 和 join 的机制。通常情况下

我们不需要直接集成 ForkJoinTask 类,只需要继承它的子类,Fork/Join 框架提供了两个子类:

RecursiveAction:用于没有返回结果的任务

RecursiveTask:用于有返回结果的任务

ForkJoinPool:ForkJoinTask 需要通过 ForkJoinPool 来执行

RecursiveTask: 继承后可以实现递归(自己调自己)调用的任务


13.CompletableFuture异步回调


有返回值的异步任务	supplyAsync


没有返回值的异步任务	runAsync


```
public class CompletableFutureDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        CompletableFuture<Void> completableFuture1 = CompletableFuture.runAsync(()->{
            System.out.println(Thread.currentThread().getName());
        });
        completableFuture1.get();

        CompletableFuture<Integer> completableFuture2 = CompletableFuture.supplyAsync(()->{
            System.out.println(Thread.currentThread().getName());
            int i = 1 / 0;
            return 1024;
        });
        completableFuture2.whenComplete((t,u)->{
            System.out.println(t);//返回值
            System.out.println(u);//异常信息
        }).get();

    }
}
```






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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值