Synchronized与Lock

高并发场景

多个线程对同一资源对象进行操作时,会产生高并发场景。

加锁

  1. synchronized
    • 同步方法:看起来锁的是方法,实际锁的是对象this
    • 同步代码块:锁的是共享资源对象
  2. Lock-可重入锁
    • 使用ReentrantLock类来实现,ReentrantLock类实现了Lock接口

同步方法:

package com.edgar.syn;

import java.util.concurrent.locks.ReentrantLock;
//synchronized是隐式锁,出了作用域自动释放,有代码块锁和方法锁
//Lock可重入锁,显示锁,只有代码块锁,JVM将花费较少的时间来调度线程,性能更好
//优先使用顺序:Lock>同步代码块>同步方法
//不安全的买票
public class TestLock {

    public static void main(String[] args) {
        BuyTicket buyTicket = new BuyTicket();
        new Thread(buyTicket,"小明").start();
        new Thread(buyTicket,"小红").start();
        new Thread(buyTicket,"黄牛").start();

    }
}


class TestLock2 implements Runnable{

    private int ticketNums=10000;//总票数
    private boolean flag=true;//停止标志位
    private final ReentrantLock lock=new ReentrantLock();

    @Override
    public void run() {
        while(flag){
            try {
                lock.lock();//加锁
                buyTicket();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                lock.unlock();//解锁
            }
        }
    }


    //买票
    //synchronized 同步方法,锁的是this
    public void buyTicket() throws InterruptedException {
        //判断是否还有票
        if(ticketNums<=0){
            flag=false;
            return;
        }


        System.out.println(Thread.currentThread().getName()+"买到了第"+(ticketNums--)+"张票");
    }
}

同步代码块:

package com.edgar.syn;

//不安全的取钱
//两个人去银行取钱
public class UnSafeBank {

    public static void main(String[] args) {

        Account account = new Account(100, "结婚基金");
        Drawing you = new Drawing(account, 50, "you");
        Drawing youGril = new Drawing(account, 100, "youGril");
        youGril.start();
        you.start();
    }
}

class Account {
    int money;
    String cardName;

    public Account(int money, String cardName) {
        this.money = money;
        this.cardName = cardName;
    }
}

class Drawing extends Thread {
    Account account;
    int drawMoney;
    int nowMoney;

    public Drawing(Account account, int drawMoney, String name) {
        super.setName(name);
        this.account = account;
        this.drawMoney = drawMoney;
    }

    @Override
    public void run() {
        //同步块,锁的是同一资源的对象
        synchronized (account) {
            if (account.money- drawMoney<= 0) {
                System.out.println("结婚基金取完了");
                return;
            }
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //卡内余额
            account.money = account.money - drawMoney;
            //你手里的钱
            nowMoney = nowMoney + drawMoney;
            System.out.println(account.cardName + "余额" + account.money);
            System.out.println(this.getName() + "手里的钱" + nowMoney);

        }
    }


}

Lock:

package com.edgar.syn;

import java.util.concurrent.locks.ReentrantLock;
//synchronized是隐式锁,出了作用域自动释放,有代码块锁和方法锁
//Lock可重入锁,显示锁,只有代码块锁,JVM将花费较少的时间来调度线程,性能更好
//优先使用顺序:Lock>同步代码块>同步方法
//不安全的买票
public class TestLock {

    public static void main(String[] args) {
        BuyTicket buyTicket = new BuyTicket();
        new Thread(buyTicket,"小明").start();
        new Thread(buyTicket,"小红").start();
        new Thread(buyTicket,"黄牛").start();

    }
}


class TestLock2 implements Runnable{

    private int ticketNums=10000;//总票数
    private boolean flag=true;//停止标志位
    private final ReentrantLock lock=new ReentrantLock();

    @Override
    public void run() {
        while(flag){
            try {
                lock.lock();//加锁
                buyTicket();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                lock.unlock();//解锁
            }
        }
    }


    //买票
    //synchronized 同步方法,锁的是this
    public void buyTicket() throws InterruptedException {
        //判断是否还有票
        if(ticketNums<=0){
            flag=false;
            return;
        }


        System.out.println(Thread.currentThread().getName()+"买到了第"+(ticketNums--)+"张票");
    }
}

Synchronized与Lock的对比

  1. synchronized是隐式锁,出了作用域自动释放,有代码块锁和方法锁
  2. Lock是显示锁,只有代码块锁,JVM将花费较少的时间来调度线程,性能更好
  3. 优先使用顺序:Lock>同步代码块>同步方法
posted @ 2021-04-15 22:05  EdgarStudy  阅读(53)  评论(0编辑  收藏  举报