Java JUC并发之synchronized与Lock的区别

四、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 版

面试的笔试题:单例模式 排序算法 生产者-消费者问题

存在问题:
如果存在A B C D 四个线程的话,是否还可以得到正常的结果?
if => 判断一次,会导致虚假唤醒

虚假唤醒: 在多线程执行过程中,线程间的通信未按照我们设想的顺序唤醒,故而出现数据不一致的问题,得到的结果不符合我们的预期。

注意:同步方法中使用while循环判断可防止虚假唤醒

生产者和消费者问题 JUC 版

Synchronized : wait() notify() => 本地方法 继承Object

Lock: await() signal() => 通过监视器Condition来调用

public class B {
    public static void main(String[] args) {

        Data02 data = new Data02();

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

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

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

        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"D").start();
    }
}
// 判断等待 业务 通知
// 资源类
class Data02{ // 数字  独立 耦合
    private int num = 0;
    Lock lock = new ReentrantLock();
    Condition condition = lock.newCondition(); // 替代同步监控器
    // +1
    public  void increment() throws InterruptedException {
        lock.lock();
        try {
            while( num != 0){  // if 判断会导致虚假唤醒
                // 等待
                condition.await();
            }
                num++;
                System.out.println(Thread.currentThread().getName() + "=>" + num);
                // 通知其他线程 +1完毕
                condition.signalAll();
        } finally {
            lock.unlock();
        }

    }


    // -1
    public void decrement() throws InterruptedException {

        lock.lock();


        try {
            while (num == 0) {

                //等待
                condition.await();
            }
            num--;
            System.out.println(Thread.currentThread().getName() + "=>" + num);
            // 通知其他线程-1完毕
            condition.signalAll();

        } finally {
            lock.unlock();

        }

    }
}

任何一个新的技术,绝对不仅仅是覆盖了原来的技术,有优势和补充!

Condition的优势?=> 实现精准通知唤醒

问题: 现在线程是随机执行的 如何让线程有序执行?

设置一个标志位,每个线程都配置一个同步监视器Condition

/**
 * @author liuzhihao  1332673139@qq.com
 * A 执行完调用B , B执行完调用C ,C执行完调用A
 */
public class C {

    public static void main(String[] args) {

        Data03 data03 = new Data03();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                data03.printA();
            }

        },"A").start();

        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                data03.printB();
            }
        },"B").start();

        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                data03.printC();
            }

        },"C").start();
    }

}

class Data03{ // 资源类 lock


    // 私有成员变量
    private Lock lock = new ReentrantLock();

    private int num = 1; // 1 A 2 B 3 C

    private Condition condition1 = lock.newCondition();
    private Condition condition2 = lock.newCondition();
    private Condition condition3 = lock.newCondition();

    public void printA() {

        lock.lock();

        try {
            // 业务代码 ,等待判断 -> 执行 -> 通知

            while ( num!= 1) {
                // 等待
                condition1.await();
            }

            System.out.println(Thread.currentThread().getName() + "AAAAAAA");

            num = 2;
            // 唤醒指定的人
            condition2.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }

    }
    public void printB() {

        lock.lock();

        try {
            // 业务代码 ,等待判断 -> 执行 -> 通知

            while (num != 2) {
                // 等待
                condition2.await();
            }

            System.out.println(Thread.currentThread().getName() + "BBBBBB");
            num = 3;
            // 唤醒 C
            condition3.signal();

        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }

    }
    public void printC() {

        lock.lock();

        try {
            // 业务代码 ,等待判断 -> 执行 -> 通知

            while (num != 3) {
                // 等待
                condition3.await();
            }
            System.out.println(Thread.currentThread().getName() + "CCCCCCC");

            num = 1;
            // 唤醒A
            condition1.signal();

        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

}
posted @ 2021-07-15 16:40  夕立君  阅读(87)  评论(0编辑  收藏  举报