Java 并发编程知识总结【四】

5. 线程通信

5.1 Lock 接口

是什么:Lock 实现提供比使用 synchronized 方法和语句可以获得的更广泛的锁定操作。 它们允许更灵活的结构化,可能具有完全不同的属性,并且可以支持多个相关联的对象 Condition

Lock 接口的实现 ReentrantLock 可重入锁

Lock l = ...;
l.lock();
try {
    
    
    // access the resource protected by this lock
} finally {
    
    
    l.unlock();
}

synchronized 与 Lock 的区别两者区别:

  1. 首先 synchronized 是 java 内置关键字,在 jvm 层面,Lock 是个 java 类(接口)
  2. synchronized 无法判断是否获取锁的状态,Lock 可以判断是否获取到锁
  3. synchronized 会自动释放锁(a线程执行完同步代码会释放锁;b线程执行过程中发生异常会释放锁),Lock 需在 finally 中手工释放锁(unlock() 方法释放锁),否则容易造成线程死锁
  4. 用 synchronized 关键字的两个线程1和线程2,如果当前线程1获得锁,线程2线程等待。如果线程1阻塞,线程2则会一直等待下去,而 Lock 锁就不一定会等待下去,如果尝试获取不到锁,线程可以不用一直等待就结束了
  5. synchronized 的锁可重入、不可中断、非公平,而 Lock 锁可重入、可判断、可公平(两者皆可)
  6. Lock 锁适合大量同步的代码的同步问题,synchronized 锁适合代码少量的同步问题。

5.2 线程通信

  1. 生产者+消费者
  2. 通知等待唤醒机制

多线程编程模板:

  • 在高内聚、低耦合的前提下,线程 操作(对外暴露的调用方法,自身的方法) 资源类

高内聚:自己应带的东西自己带着,并对外暴露(空调有制冷和制热是出厂就带着的,但是人不带着制冷和制热)

低耦合(拆分):eg:前后端分离、淘宝与顺丰之间的关系,但是淘宝内部没有与顺丰相关的、顺丰内部也没有与淘宝相关的

  • 判断 —> 干活 —> 通知
  • 防止虚假唤醒用 while
  • 注意修改标志位

案例:现在两个线程,可以操作初始值为零的一个变量,实现一个线程对该变量加1,一个线程对该变量减1,交替,来10轮。

Synchronized 实现

// 资源类
class AirConditioner {
    
    
    private int number = 0;

    public synchronized void increment() throws InterruptedException {
    
    
        // 1. 判断
        while (number != 0) {
    
    
            this.wait();
        }
        // 2. 干活
        ++number;
        SmallTool.printTimeAndThread(String.valueOf(number));
        // 3. 通知
        this.notifyAll();
    }

    public synchronized void decrement() throws InterruptedException {
    
    
        // 1. 判断
        while (number == 0) {
    
    
            this.wait();
        }
        // 2. 干活
        --number;
        SmallTool.printTimeAndThread(String.valueOf(number));
        // 3. 通知
        this.notifyAll();
    }
}
public static void main(String[] args) {
    
    
    AirConditioner airConditioner = new AirConditioner();

    new Thread(() -> {
    
    
        for (int i = 1; i <= 10; i++) {
    
    
            try {
    
    
                airConditioner.increment();
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
        }
    }, "A").start();

    new Thread(() -> {
    
    
        for (int i = 1; i <= 10; i++) {
    
    
            try {
    
    
                airConditioner.decrement();
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
        }
    }, "B").start();

    new Thread(() -> {
    
    
        for (int i = 1; i <= 10; i++) {
    
    
            try {
    
    
                airConditioner.increment();
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
        }
    }, "C").start();

    new Thread(() -> {
    
    
        for (int i = 1; i <= 10; i++) {
    
    
            try {
    
    
                airConditioner.decrement();
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
        }
    }, "D").start();
}

Java8 新版本实现

image-20230101151808311

Condition

扫描二维码关注公众号,回复: 14679769 查看本文章

image-20230101152415051

代码实现

// 资源类
class AirConditioner {
    
    
    private int number = 0;

    private final Lock lock = new ReentrantLock();

    private final Condition condition = lock.newCondition();

    public void increment() {
    
    
        lock.lock();
        try {
    
    
            // 1. 判断
            while (number != 0) {
    
    
                condition.await();
            }
            // 2. 干活
            ++number;
            SmallTool.printTimeAndThread(String.valueOf(number));
            // 3. 通知
            condition.signalAll();
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            lock.unlock();
        }
    }

    public void decrement() {
    
    
        lock.lock();
        try {
    
    
            // 1.判断
            while (number == 0) {
    
    
                condition.await();
            }
            // 2.干活
            number--;
            SmallTool.printTimeAndThread(String.valueOf(number));
            // 3.通知
            condition.signalAll();
        } catch (Exception e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            lock.unlock();
        }
    }
}
public static void main(String[] args) {
    
    
    AirConditioner airConditioner = new AirConditioner();

    new Thread(() -> {
    
    
        for (int i = 1; i <= 10; i++) {
    
    
            airConditioner.increment();
        }
    }, "A").start();

    new Thread(() -> {
    
    
        for (int i = 1; i <= 10; i++) {
    
    
            airConditioner.decrement();
        }
    }, "B").start();

    new Thread(() -> {
    
    
        for (int i = 1; i <= 10; i++) {
    
    
            airConditioner.increment();
        }
    }, "C").start();

    new Thread(() -> {
    
    
        for (int i = 1; i <= 10; i++) {
    
    
            airConditioner.decrement();
        }
    }, "D").start();
}

5.3 线程间定制化调用通信

案例:多线程之间按顺序调用,实现A->B->C,三个线程启动,要求如下:AA打印1次,BB打印2次,CC打印3次,接着,AA打印1次,BB打印2次,CC打印3次,来4轮

// 资源类
class ShareResource {
    
    
    /**
     * 1:A 2:B 3:C
     */
    private int number = 1;

    private final Lock lock = new ReentrantLock();

    /**
     * A 的监视器
     */
    private final Condition condition1 = lock.newCondition();

    /**
     * B 的监视器
     */
    private final Condition condition2 = lock.newCondition();

    /**
     * C 的监视器
     */
    private final Condition condition3 = lock.newCondition();

    public void print1() {
    
    
        lock.lock();
        try {
    
    
            // 1. 判断
            while (number != 1) {
    
    
                condition1.await();
            }
            // 2. 干活
            SmallTool.printTimeAndThread(String.valueOf(number));
            // 修改标志位
            number = 2;
            // 3. 实现精确通知
            condition2.signal();
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            lock.unlock();
        }
    }

    public void print2() {
    
    
        lock.lock();
        try {
    
    
            // 1. 判断
            while (number != 2) {
    
    
                condition2.await();
            }
            // 2. 干活
            for (int i = 1; i <= 2; i++) {
    
    
                SmallTool.printTimeAndThread(String.valueOf(number));
            }
            // 修改标志位
            number = 3;
            // 3. 实现精确通知
            condition3.signal();
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            lock.unlock();
        }
    }

    public void print3() {
    
    
        lock.lock();
        try {
    
    
            // 1. 判断
            while (number != 3) {
    
    
                condition3.await();
            }
            // 2. 干活
            for (int i = 1; i <= 3; i++) {
    
    
                SmallTool.printTimeAndThread(String.valueOf(number));
            }
            // 修改标志位
            number = 1;
            // 3. 实现精确通知
            condition1.signal();
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            lock.unlock();
        }
    }
}
public static void main(String[] args) {
    
    
    ShareResource shareResource = new ShareResource();

    new Thread(() -> {
    
    
        for (int i = 1; i <= 4; i++) {
    
    
            shareResource.print1();
        }
    }, "A").start();

    new Thread(() -> {
    
    
        for (int i = 1; i <= 4; i++) {
    
    
            shareResource.print2();
        }
    }, "B").start();

    new Thread(() -> {
    
    
        for (int i = 1; i <= 4; i++) {
    
    
            shareResource.print3();
        }
    }, "C").start();
}
// 结果
1672558974888	|	24	|	A	|	1
1672558974889	|	25	|	B	|	2
1672558974889	|	25	|	B	|	2
1672558974889	|	26	|	C	|	3
1672558974889	|	26	|	C	|	3
1672558974889	|	26	|	C	|	3
1672558974889	|	24	|	A	|	1
1672558974889	|	25	|	B	|	2
1672558974889	|	25	|	B	|	2
1672558974890	|	26	|	C	|	3
1672558974890	|	26	|	C	|	3
1672558974890	|	26	|	C	|	3
1672558974890	|	24	|	A	|	1
1672558974890	|	25	|	B	|	2
1672558974890	|	25	|	B	|	2
1672558974890	|	26	|	C	|	3
1672558974890	|	26	|	C	|	3
1672558974890	|	26	|	C	|	3
1672558974890	|	24	|	A	|	1
1672558974890	|	25	|	B	|	2
1672558974890	|	25	|	B	|	2
1672558974890	|	26	|	C	|	3
1672558974890	|	26	|	C	|	3
1672558974890	|	26	|	C	|	3

更多文章在我的语雀平台:https://www.yuque.com/ambition-bcpii/muziteng

猜你喜欢

转载自blog.csdn.net/m0_52781902/article/details/128534596
今日推荐