并发编程(三)共享模型之管程(下)

 十一、重新理解线程状态转换

并发编程(三)共享模型之管程(下)_第1张图片

假设有线程 【Thread t 】

 并发编程(三)共享模型之管程(下)_第2张图片

并发编程(三)共享模型之管程(下)_第3张图片

并发编程(三)共享模型之管程(下)_第4张图片

并发编程(三)共享模型之管程(下)_第5张图片

十二、多把锁

并发编程(三)共享模型之管程(下)_第6张图片

并发编程(三)共享模型之管程(下)_第7张图片

 将锁的粒度细分:

好处:增强并发度。

坏处:如果一个线程需要同时获得多把锁,就容易发生死锁。

十三、活跃性

1. 死锁

一个线程需要同时获取多把锁,这时就容易发生死锁。

【t1 线程】 获得 A对象 锁,接下来想获取 B对象的锁;

【t2 线程】 获得 B对象 锁,接下来想获取 A对象的锁。

并发编程(三)共享模型之管程(下)_第8张图片

并发编程(三)共享模型之管程(下)_第9张图片  

2. 定位死锁

检测死锁可以使用 jconsole工具,

或者使用 jps 定位进程 id,再用 jstack 定位死锁:

并发编程(三)共享模型之管程(下)_第10张图片

并发编程(三)共享模型之管程(下)_第11张图片

3. 哲学家就餐问题

并发编程(三)共享模型之管程(下)_第12张图片

并发编程(三)共享模型之管程(下)_第13张图片

并发编程(三)共享模型之管程(下)_第14张图片

并发编程(三)共享模型之管程(下)_第15张图片

并发编程(三)共享模型之管程(下)_第16张图片

这种线程没有按预期结束,执行不下去的情况,归类为【活跃性】问题,除了死锁以外,还有活锁饥饿者两种情况。 

4. 活锁

活锁出现在两个线程互相改变对方的结束条件,最后谁也无法结束。

并发编程(三)共享模型之管程(下)_第17张图片

5. 饥饿

很多教程中把饥饿定义为,一个线程由于优先级太低,始终得不到 CPU 调度执行,又不能够结束,饥饿的情况不易演示,讲读写锁时会涉及饥饿问题。

下面我讲一下我遇到的一个线程饥饿的例子,先来看看使用顺序加锁的方式解决之前的死锁问题

并发编程(三)共享模型之管程(下)_第18张图片

并发编程(三)共享模型之管程(下)_第19张图片

十四、ReentrantLock

相对于 synchronized 具备如下特定:

(1)可中断

(2)可以设置超市时间

(3)可以设置为公平锁

(4)支持多个条件变量

与 synchronized 一样,都支持可重入

并发编程(三)共享模型之管程(下)_第20张图片

1. 可重入

可重入是指同一个线程如果首次获得了这把锁,那么因为它是这把锁的拥有者,因此有权利再次获取这把锁。

如果是不可重入,那么第二次获得锁时,自己也会被锁挡住。

并发编程(三)共享模型之管程(下)_第21张图片

2. 可打断

并发编程(三)共享模型之管程(下)_第22张图片

并发编程(三)共享模型之管程(下)_第23张图片

3. 锁超时

并发编程(三)共享模型之管程(下)_第24张图片

4. 公平锁

ReentrantLock 默认是不公平的。

// true:公平
// false(默认):不公平
ReentrantLock lock = new ReentrantLock(true);

公平锁一般没有必要,会降低并发度,后面分析原理时会讲解。

5. 条件变量

synchronized 中也有条件变量,就是我们讲原理的 waitSet 休息室,当条件不满足时进入等待。

ReentrantLock 的条件变量比 synchronized 强大之处在于,它是支持多个条件变量的,这就好比:

(1)synchronized 是那些不满足条件的线程都在一间休息室等消息

(2)而 ReentrantLock 支持多间休息室,唤醒时也是按休息室来唤醒的

使用要点:

(1)await 前需要获得锁

(2)await 执行后,会释放锁,进入 conditionObject 等待

(3)await 的线程被唤醒(或打断、或超时)去重新竞争 lock 锁

(4)竞争 lock 锁成功后,从 await 后继续执行

并发编程(三)共享模型之管程(下)_第25张图片

public class Test24 {
    static ReentrantLock ROOM = new ReentrantLock();
    static Condition waitCigaretteQueue = ROOM.newCondition();
    static Condition waitbreakfastQueue = ROOM.newCondition();
    static volatile boolean hasCigrette = false;
    static volatile boolean hasBreakfast = false;

    public static void main(String[] args) throws InterruptedException {

        new Thread(()->{
            ROOM.lock();
            try {
                System.out.println(Thread.currentThread().getName()+":有烟没?"+hasCigrette);
                while (!hasCigrette){
                    System.out.println(Thread.currentThread().getName()+":没烟先休息会");
                    try {
                        waitCigaretteQueue.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(Thread.currentThread().getName()+":开始干活了");
            }finally {
                ROOM.unlock();
            }
        },"彭于晏").start();

        new Thread(()->{
            ROOM.lock();
            try {
                System.out.println(Thread.currentThread().getName()+":有外卖没?"+hasBreakfast);
                while (!hasBreakfast){
                    System.out.println(Thread.currentThread().getName()+":没外卖先休息会");
                    try {
                        waitbreakfastQueue.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(Thread.currentThread().getName()+":开始干活了");
            }finally {
                ROOM.unlock();
            }
        },"迪丽热巴").start();

        Thread.sleep(1000);
        new Thread(()->{
            ROOM.lock();
            try {
                hasBreakfast = true;
                waitbreakfastQueue.signal();
            }finally {
                ROOM.unlock();
            }

        },"外卖小哥").start();
    }
}

十五、 同步顺序之顺序控制

1. 固定运行顺序(先2后1)

1.1 wait notify 版

并发编程(三)共享模型之管程(下)_第26张图片  

1.2 Park Unpark 版

并发编程(三)共享模型之管程(下)_第27张图片

2. 交替输出

线程 1 输出 a 5 次,线程 2 输出 b 5 次,线程 3 输出 c 5 次。现在要求输出 abcabcabcabcabc 怎么实现

2.1 wait notify 版

并发编程(三)共享模型之管程(下)_第28张图片

并发编程(三)共享模型之管程(下)_第29张图片  

2.2 Lock 条件变量版

并发编程(三)共享模型之管程(下)_第30张图片

并发编程(三)共享模型之管程(下)_第31张图片  

2.3 Park Unpark 版

并发编程(三)共享模型之管程(下)_第32张图片

并发编程(三)共享模型之管程(下)_第33张图片  

你可能感兴趣的:(JUC并发编程,java,开发语言,后端,并发编程)