多线程中锁的基础运用

以一段简单的代码来展示一下多线程会出现的问题

public class blog {
    public static void main(String[] args) {
        GoodsNum goodsNum=new GoodsNum(10);
        Operate operate=new Operate(goodsNum);
        new Thread(()->{
            while (goodsNum.getNum()>0){
                operate.sale();
            }
        },"1").start();
        new Thread(()->{
            while (goodsNum.getNum()>0){
                operate.sale();
            }
        },"2").start();
    }
}
class GoodsNum {
    private int num;
    public GoodsNum() {
    }
    public GoodsNum(int num) {
        this.num = num;
    }

    public int getNum() {
        return num;
    }

    public void setNum(int num) {
        this.num = num;
    }
}
class Operate {
    private GoodsNum goods;

    public Operate(GoodsNum goods) {
        this.goods = goods;
    }
    public void sale(){
        if(goods.getNum()>0) {
            System.out.println(Thread.currentThread().getName() + ":第" + goods.getNum() + "件卖出剩余" + (goods.getNum() - 1) + "件");
            goods.setNum(goods.getNum() - 1);
        }
    }
}

由于多线程执行的结果是不可控的,所以代码执行结果为其中的一次

1:10件卖出剩余92:10件卖出剩余92:8件卖出剩余71:9件卖出剩余82:7件卖出剩余61:6件卖出剩余52:5件卖出剩余41:4件卖出剩余32:3件卖出剩余21:2件卖出剩余12:1件卖出剩余0

从执行结果中我们可以发现出现了几处不合理的地方,例如:

1:10件卖出剩余92:10件卖出剩余9

第一个线程已经卖了第10件商品但是第二个线程又卖了第10件商品,同一件商品被卖了两次是不合理的,这种情况的出现,实际上是cpu调度的问题,线程是否执行,执行多久都是由cpu决定的,可能一个线程并没有执行完,cpu就让下一个线程开始执行,让刚才未执行完的线程先处于就绪状态,这就会导致上述问题的出现。

用代码来解释一下出现两个线程卖同一个商品的情况,线程中执行的实际上是sale方法,所以用sale方法来说明

 public void sale(){
        if(goods.getNum()>0) {
            System.out.println(Thread.currentThread().getName() + ":第" + goods.getNum() + "件卖出剩余" + (goods.getNum() - 1) + "件");
            goods.setNum(goods.getNum() - 1);
        }
    }

如果第一个线程在执行时,sale方法执行到一半时cpu开始调度第二个线程,此时第一个线程会突然停止执行处于就绪状态,并且由于未执行完打印语句导致并未打印,等到再次被调度时才会打印一开始的结果,此时就会出现同一个商品被卖两次的情况。

用代码来展示锁(synchronized)的运用

class Operate {
    private GoodsNum goods;
    public Operate(GoodsNum goods) {
        this.goods = goods;
    }

    public synchronized void sale() {
        int num= goods.getNum();
            if (goods.getNum() > 0) {
                System.out.println(Thread.currentThread().getName() + ":第" + num + "件卖出剩余" + --num + "件");
                goods.setNum(num);
            }
    }
}

在实例对象中加锁实际上是在给对象加锁而不是给实例方法加锁,在加锁后当一个线程拿到对象锁后可以执行它方法,而其它线程就拿不到锁也就无法执行对象的方法需要等待拿锁线程执行完方法,才有机会拿锁并执行方法,这样线程会更加安全,不会出现以下结果

1:10件卖出剩余92:10件卖出剩余92:8件卖出剩余71:9件卖出剩余8

可保证商品不重卖和顺序卖出,但加锁后会降低代码执行效率,因为在一个线程在执行时其它线程处于阻塞状态。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值