当前位置:   article > 正文

并发编程尚硅谷笔记

并发编程尚硅谷笔记

并发编程

网课链接 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(监视器)

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



用户线程	自定义线程



守护线程	比如垃圾回收

没有用户线程,守护线程也会结束
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58

2.Lock接口


synchronizd	同步锁

卖票案例



多线程编程步骤一

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

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



创建线程的多种方式

继承Thread类	少用

实现Runnable接口

使用Callable接口

使用线程池



Lock接口	java.util.concurrent.locks

需要手动上锁和释放锁

实现类

ReentrantLock	可重入锁	

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

卖票案例



Lock和synchronized去呗

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

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


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48

3.线程间通信


多线程编程步骤二

资源类

判断

干活

通知



synchronized实现线程间通信

wait

notifyAll



虚假唤醒问题

循环判断while解决



Lock实现线程间通信

condition

await

signalAll



  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

4.线程间定制化通信

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

通过标志位实现

  • 1
  • 2
  • 3
  • 4

5.集合的线程安全

Arraylist线程不安全演示

java.util.ConcurrentModificationException

并发修改异常



解决方案

1)Vector

2)Collections

3)CopyOnWriteArraylist

读的时候支持并发读

写的时候独立写



HashSet线程不安全	不重复 无序

CopyOnWriteArraySet



HashMap线程不安全

ConcurrentHashMap


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

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所占用的资源

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61

7.Callable接口


创建线程方法

继承Thread类

实现Runnable接口

通过Callable接口	

线程池方式



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



Callable接口	和	Runnable

是否有返回值



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



Runnable接口有实现类FutureTask


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

8.JUC的强大辅助类


减少计数	CounutDownLatch	

await	变成0后输出

countDown	-1





循环栅栏	CyclicBarrier

await	





信号灯	Semaphore

acquire

release



  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

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();


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56

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	不可用	不可用



  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97

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()才会创建

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

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


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68

12.Fork/Join分支合并框架


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

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



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

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

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

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

ForkJoinPool:ForkJoinTask 需要通过 ForkJoinPool 来执行

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


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/爱喝兽奶帝天荒/article/detail/966813
推荐阅读
相关标签
  

闽ICP备14008679号