高并发下关于锁的问题

两种锁synchronize和lock区别?
  • 1、synchronize是内置的java关键字,lock是一个java类
  • 2、synchronize无法判断获取锁的状态,lock可以判断是否获取到了锁
  • 3、synchronize会自动释放锁,lock必须手动释放锁。如果不释放会造成死锁问题
  • 4、synchronize线程1(获得锁,阻塞)、线程2(等待,傻傻的等),lock锁就不一定会等待下去
  • 5、synchronize可重入锁,不可以中断,非公平。lock,可重入锁,可以判断锁,非公平(可调)
  • 6、synchronize适合少量的代码同步问题,lock适合大量的同步代码

以下通过生产者消费者问题举例说明:

synchronize锁解决生产者消费者问题

/**
 * Description:synchronize()锁解决生产者消费者问题
 * Author:Jizaichun  Date:2022/6/14 16:58
 */
/*
线程之间的通信间题:生产者和消费者间题!等待唤醒,通知唤醒
线程交替执行A B操作同一个变量    num =0
A num+1
B num-1
*/
public class A {
    public static void main(String[] args) {
        Data data = new Data();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    data.increment();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }, "A").start();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }, "B").start();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    data.increment();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }, "C").start();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }, "D").start();
    }
}

// 等待,业务,通知
class Data {// 数字 资源类
    private int number = 0;

    // +1
    public synchronized void increment() throws InterruptedException {
        while (number != 0) {
            // 等待
            this.wait();
        }
        number++;
        System.out.println(Thread.currentThread().getName() + "=>" + number);
        // 通知其它线程,+1完毕
        this.notifyAll();

    }

    // -1
    public synchronized void decrement() throws InterruptedException {
        while (number == 0) {
            // 等待
            this.wait();
        }
        number--;
        System.out.println(Thread.currentThread().getName() + "=>" + number);
        // 通知其它线程,-1完毕
        this.notifyAll();
    }
}

注意 !!!

while (number != 0) {
    // 等待
    this.wait();
}

// 此处代码块必须用while,如果使用if会造成虚假唤醒问题
/**
 * 具体:假设 number此时等于1,即已经被生产了产品如果这里用的是if判断,
 * 如果此时A,C两个生产者线程争夺increment()方法执行权假设A拿到执行权,
 * 经过判断number!=0成立,则A.wait()开始等待(wait()会释放锁),
 * 然后C试图去执行生产方法,但依然判断number!=0成立,则B.wait()开始等待(wait()会释放锁)
 * 碰巧这时候消费者线程线程B/D去消费了一个产品,使number=0然后,B/D消费完后调用this.notifyAll();
 * 这时候2个等待中的生产者线程继续生产产品,而此时number++ 执行了2次同理,重复上述过程,生产者线程继续wait()等待,
 * 消费者调用this.notifyAll();然后生产者继续超前生产,最终导致‘产能过剩’,即number大于1
 * 
 */

lock锁解决生产者消费者问题

/**
 * Description:lock()锁解决生产者消费者问题
 * Author:Jizaichun  Date:2022/6/14 19:10
 */
public class B {
    public static void main(String[] args) {
        Data2 data = new Data2();

        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 Data2 { // 数字 资源类

    private int number = 0;

    Lock lock = new ReentrantLock();
    Condition condition = lock.newCondition();

    // condition.await(); // 等待
    // condition.signalAll(); // 唤醒全部
    //+1
    public void increment() throws InterruptedException {

        lock.lock();
        try {
            // 业务代码
            while (number != 0) {
                // 等待
                condition.await();
            }
            number++;
            System.out.println(Thread.currentThread().getName() + "=>" + number);
            // 通知其他线程,我+1完毕了
            condition.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    //-1
    public void decrement() throws InterruptedException {
        lock.lock();
        try {
            while (number == 0) {
                // 等待
                condition.await();
            }
            number--;
            System.out.println(Thread.currentThread().getName() + "=>" + number);
            // 通知其他线程,我-1完毕了
            condition.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

lock锁配合Condition进行细粒度化操作

/**
 * Description:通过Condition实现A执行完调用B,B执行完调用C,C执行完再调A,形成一个循环
 * Author:Jizaichun  Date:2022/6/14 19:23
 */
public class C {
    public static void main(String[] args) {
        Data3 data = new Data3();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                data.printA();
            }
        }, "A").start();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                data.printB();
            }
        }, "B").start();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                data.printC();
            }
        }, "C").start();
    }
}

class Data3 {// 资源类
    private int number = 1;// 1A  2B  3C
    private final Lock lock = new ReentrantLock();
    Condition condition1 = lock.newCondition();
    Condition condition2 = lock.newCondition();
    Condition condition3 = lock.newCondition();


    public void printA() {
        lock.lock();
        try {
            // 判断、执行、通知
            while (number != 1) {
                // 等待
                condition1.await();
            }
            System.out.println(Thread.currentThread().getName() + "=>AAAA");
            // 唤醒,通知指定的监视器
            number = 2;
            condition2.signal();
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            lock.unlock();
        }
    }

    public void printB() {
        lock.lock();
        try {
            while (number != 2) {
                condition2.await();
            }
            System.out.println(Thread.currentThread().getName() + "=>BBBB");
            number = 3;
            condition3.signal();
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            lock.unlock();
        }
    }

    public void printC() {
        lock.lock();
        try {
            while (number != 3) {
                condition3.await();
            }
            System.out.println(Thread.currentThread().getName() + "=>CCCC");
            number = 1;
            // 通知condition1监视器
            condition1.signal();
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            lock.unlock();
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@Jizaichun

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值