线程同步 synchronized 和 Lock 的区别

synchronized 和 Lock 的区别:
① synchronized是内置的Java关键字,Lock是一个接口
② synchronized无法判断是否获取到锁,Lock可以判断是否获取到锁
③ synchronized会自动释放锁,Lock必须要手动释放锁,否则可能会死锁!
④ synchronized当有两个线程,其中一个得到锁,另一个线程则死等,Lock不一定会死等
⑤ synchronized是可重入锁 不可中断的 非公平锁,Lock是可重入锁 可以判断锁 可设为公平锁
⑥ synchronized适合锁少量的代码同步问题,Lock适合锁大量的同步代码
卖票举例:

① 使用synchronized进行线程同步:

public class Demo01 {
    public static void main(String[] args) {
        // 并发,多线程操作统一资源
        Ticket ticket = new Ticket();

        new Thread(()->{ // Lambda表达式
            for (int i = 0; i < 60; i++) {
                ticket.saleTicket();
            }
        },"张三").start();
        new Thread(()->{
            for (int i = 0; i < 60; i++) {
                ticket.saleTicket();
            }
        },"李四").start();
        new Thread(()->{
            for (int i = 0; i < 60; i++) {
                ticket.saleTicket();
            }
        },"王五").start();
    }
}
class Ticket{
    private int number = 50;

    public synchronized void saleTicket(){ // 同步方法
        if (number>0){
            System.out.println(Thread.currentThread().getName()+"卖出了第"+(number--)+"张票");
        }
    }
}

结果:

张三卖出了第50张票
张三卖出了第49张票
张三卖出了第48张票
张三卖出了第47张票
......(此处省略)
张三卖出了第5张票
张三卖出了第4张票
张三卖出了第3张票
张三卖出了第2张票
张三卖出了第1张票

② 使用Lock进行线程同步:

public class Demo02 {
    public static void main(String[] args) {
        // 并发,多线程操作统一资源
        Ticket2 ticket = new Ticket2();

        // Lambda表达式
        new Thread(()->{ for (int i = 0; i < 60; i++) ticket.saleTicket(); },"张三").start();
        new Thread(()->{ for (int i = 0; i < 60; i++) ticket.saleTicket(); },"李四").start();
        new Thread(()->{ for (int i = 0; i < 60; i++) ticket.saleTicket(); },"王五").start();
    }
}
class Ticket2{
    private int number = 50;
    Lock lock = new ReentrantLock();

    public void saleTicket(){
        lock.lock(); // 加锁
        try{
            if (number>0){
                System.out.println(Thread.currentThread().getName()+"卖出了第"+(number--)+"张票");
            }
        }finally {
            lock.unlock(); // 解锁
        }
    }
}

结果:

张三卖出了第50张票
张三卖出了第49张票
张三卖出了第48张票
张三卖出了第47张票
张三卖出了第46张票
......(此处省略)
张三卖出了第5张票
张三卖出了第4张票
张三卖出了第3张票
张三卖出了第2张票
张三卖出了第1张票
生产者消费者问题

线程之间交替操作num,当num==0时,num加一,当num>0时,num减一
① 使用synchronized进行线程同步:

public class Demo03 {
    public static void main(String[] args) {
        Num num = new Num();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    num.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"A").start();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    num.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"B").start();
    }
}
class Num{
    private int num = 0;
    // +1:当num==0时,加一
    public synchronized void increment() throws InterruptedException {
        if (num!=0){
            this.wait(); // 等待
        }
        num++;
        System.out.println(Thread.currentThread().getName()+"-->"+num);
        this.notifyAll(); // 唤醒,通知其他线程+1完毕
    }
    // -1:当num>0时,减一
    public synchronized void decrement() throws InterruptedException {
        if (num==0){
            this.wait(); // 等待
        }
        num--;
        System.out.println(Thread.currentThread().getName()+"-->"+num);
        this.notifyAll(); // 唤醒,通知其他线程-1完毕
    }
}

结果:

A-->1
B-->0
A-->1
B-->0
A-->1
B-->0
A-->1
B-->0
A-->1
B-->0
A-->1
B-->0
A-->1
B-->0
A-->1
B-->0
A-->1
B-->0
A-->1
B-->0

当有线程超过两个时,可能会出现虚假唤醒的情况,所以判断语句用while循环,避免虚假唤醒

public class Demo04 {
    public static void main(String[] args) {
        Num2 num = new Num2();
        new Thread(()->{
            for (int i = 0; i < 5; i++) {
                try {
                    num.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"A").start();
        new Thread(()->{
            for (int i = 0; i < 5; i++) {
                try {
                    num.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"B").start();
        new Thread(()->{
            for (int i = 0; i < 5; i++) {
                try {
                    num.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"C").start();
        new Thread(()->{
            for (int i = 0; i < 5; i++) {
                try {
                    num.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"D").start();
    }
}
class Num2{
    private int num = 0;
    // +1:当num==0时,加一
    public synchronized void increment() throws InterruptedException {
        while (num!=0){  // 使用while循环,避免虚假唤醒
            this.wait(); // 等待
        }
        num++;
        System.out.println(Thread.currentThread().getName()+"-->"+num);
        this.notifyAll(); // 唤醒,通知其他线程+1完毕
    }
    // -1:当num>0时,减一
    public synchronized void decrement() throws InterruptedException {
        while (num==0){  // 使用while循环,避免虚假唤醒
            this.wait(); // 等待
        }
        num--;
        System.out.println(Thread.currentThread().getName()+"-->"+num);
        this.notifyAll(); // 唤醒,通知其他线程-1完毕
    }
}

结果:

A-->1
B-->0
A-->1
B-->0
A-->1
B-->0
A-->1
B-->0
A-->1
B-->0
C-->1
D-->0
C-->1
D-->0
C-->1
D-->0
C-->1
D-->0
C-->1
D-->0

② 使用Lock进行线程同步:
Condition:同步监视器

public class Demo05 {
    public static void main(String[] args) {
        Num3 num = new Num3();
        new Thread(()->{
            for (int i = 0; i < 5; i++) {
                try {
                    num.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"A").start();
        new Thread(()->{
            for (int i = 0; i < 5; i++) {
                try {
                    num.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"B").start();
        new Thread(()->{
            for (int i = 0; i < 5; i++) {
                try {
                    num.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"C").start();
        new Thread(()->{
            for (int i = 0; i < 5; i++) {
                try {
                    num.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"D").start();
    }
}
class Num3{
    private int num = 0;
    Lock lock = new ReentrantLock();
    Condition condition = lock.newCondition();

    // +1:当num==0时,加一
    public void increment() throws InterruptedException {
        lock.lock();
        try {
            while (num!=0){
                condition.await(); // 等待 相当于synchronized中的wait()
            }
            num++;
            System.out.println(Thread.currentThread().getName()+"-->"+num);
            condition.signalAll(); // 唤醒,通知其他线程+1完毕 相当于synchronized中的notifyAll()
        }finally {
            lock.unlock();
        }
    }
    // -1:当num>0时,减一
    public void decrement() throws InterruptedException {
        lock.lock();
        try {
            while (num==0){
                condition.await(); // 等待 相当于synchronized中的wait()
            }
            num--;
            System.out.println(Thread.currentThread().getName()+"-->"+num);
            condition.signalAll(); // 唤醒,通知其他线程-1完毕 相当于synchronized中的notifyAll()
        }finally {
            lock.unlock();
        }
    }
}

结果:

A-->1
B-->0
A-->1
B-->0
A-->1
B-->0
A-->1
B-->0
C-->1
B-->0
C-->1
D-->0
C-->1
D-->0
C-->1
D-->0
C-->1
D-->0
A-->1
D-->0

Condition 实现精准通知唤醒:

// A执行完执行B,B执行完执行C,C执行完执行A
public class Demo06 {
    public static void main(String[] args) {
        Num4 num = new Num4();
        new Thread(()->{
            for (int i = 0; i < 5; i++) {
                num.printA();
            }
        },"A").start();
        new Thread(()->{
            for (int i = 0; i < 5; i++) {
                num.printB();
            }
        },"B").start();
        new Thread(()->{
            for (int i = 0; i < 5; i++) {
                num.printC();
            }
        },"C").start();
    }
}
class Num4{
    private int num = 1;
    private Lock lock = new ReentrantLock();
    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(); //等待
            }
            num = 2;
            System.out.println(Thread.currentThread().getName()+"-->"+"AAA");
            condition2.signal(); // 唤醒B
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
    public void printB(){
        lock.lock();
        try {
            while (num!=2){
                condition2.await(); //等待
            }
            num = 3;
            System.out.println(Thread.currentThread().getName()+"-->"+"BBB");
            condition3.signal(); // 唤醒C
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
    public void printC(){
        lock.lock();
        try {
            while (num!=3){
                condition3.await(); //等待
            }
            num = 1;
            System.out.println(Thread.currentThread().getName()+"-->"+"CCC");
            condition1.signal(); // 唤醒A
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
}

结果:

A-->AAA
B-->BBB
C-->CCC
A-->AAA
B-->BBB
C-->CCC
A-->AAA
B-->BBB
C-->CCC
A-->AAA
B-->BBB
C-->CCC
A-->AAA
B-->BBB
C-->CCC
Lock用法跟synchronized差不多,但能够显现精准唤醒 
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值