线程同步

作用

我们在日常生活中,会遇到多个人同时对一个账户取款的情况,线程同步就可以保证让一个用户取款的时候,其他用户不能对同一个账户取款。

如何实现

1.使用synchronized做锁
 Account account=new Account();

    @Override
    public void run() {
        synchronized(account){
            if(account.have()>=400){
                account.withDraw(400);
                System.out.println(Thread.currentThread().getName()+
                        "取款成功  "+"账户余额:"+account.have());
            }else{
                System.out.println(Thread.currentThread().getName()+
                        "全款失败  "+"账户余额:"+account.have());
            }
        }
    }

将临界代码放入到锁中

同步代码块原理
synchronized(account)

1.括号中的内容叫同步监视器(锁)。必须是引用类型,不能是基本数据类型。
2.为了保证安全性,不要改变同步监视器的引用,因为如果改变了同步监视器的引用,就相当于把锁改掉了。所以可以把引用修饰为final
3.一般用线程共享的资源来做锁。
4.不要拿Integer,和String的对象引用来做锁

执行的原理

1.当一个线程来到同步代码块,发现锁是open状态,锁就会close状态,然后线程开始执行其中的代码。
2.第一个线程执行过程中,发生了线程转化,第一个线程就失去了cpu,但锁依然是关闭状态。
3.第二个线程获取cpu,发现锁是close状态,不能执行其中的代码。第二个线程会进入阻塞状态,让出cpu,当第一个线程再次得到cpu会继续执行以前没执行完的代码,把代码执行完了以后,锁就会变为open状态

注意点

1.如果不同的同步代码块,使用相同的对象引用做锁,一个同步代码块的锁是close状态,其他同步代码块也会是close状态

同步方法
@Override
    public void run() {
            withDraw();
    }
    public synchronized void withDraw()  {

        if(account.have()>=400){
            account.withDraw(400);
            System.out.println(Thread.currentThread().getName()+
                    "取款成功  "+"账户余额:"+account.have());
        }else{
            System.out.println(Thread.currentThread().getName()+
                    "全款失败  "+"账户余额:"+account.have());
        }
    }

在方法的签名上加synchronized,然后再run()中调用该方法。

注意点

1.非静态同步方法的同步监视器就是this,就是你当前的类对象
2.也就是说你在该类中的其他方法加上锁时,如果一个非静态方法被锁上了,因为所有的该类中的非静态方法都使用同一个锁,所以其他方法都被锁上了
3.在静态方法上也可以加锁,该锁的同步监视器:类名.class
如果该类中的静态方法被锁上了,其他的静态方法也会被锁上。
4.因为上面的两个原因,导致同步方法的效率是非常低的。同步代码块的效率是比同步方法的效率高的,所以一般不要使用同步方法

Lock锁
private Lock lock=new ReentrantLock();
    @Override
    public void run() {
        lock.lock();
        try{
            if(account.have()>=400){
                account.withDraw(400);
                System.out.println(Thread.currentThread().getName()+
                        "取款成功  "+"账户余额:"+account.have());
            }else{
                System.out.println(Thread.currentThread().getName()+
                        "全款失败  "+"账户余额:"+account.have());
            }
        }finally {
            lock.unlock();
        }

Lock锁是属于API范围的,而synchronized是虚拟机调度的。
Lock通过对象名来调用方法,来实现锁的开闭,所以你必须要手动解锁。对于synchronized是可以自动解锁的。

注意点

1.如果在run方法内部出现异常,直接抛给调用者,这时锁话没有开。为了防止这种的情况出现,要加tryfinall
2.ReentrantLock是一种可重入锁。如果多个方法用来同一个lock,多个方法是可以进入的,也是可重入锁的含义。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值