JUC(二)--synchronized原理

线程状态

 

  •  NEW 线程刚被创建,但还没调用start方法
  • RUNNABLE 调用start方法后,包含运行状态和阻塞状态(如IO操作,此时不占用CPU资源)
  • BLOCKED,阻塞,如synchronized的时候等待别的线程释放锁
  • WAITING,等待,如调用join
  • TIMED_WAITING,限时等待,如调用sleep
  • TERMINATED,线程终止

线程安全分析 

成员变量和静态变量是否线程安全?

如果没有共享,则线程安全,如果被共享了,但只是只读,则线程安全,如果有读写操作,则要考虑线程安全

从一个90%的人都答错的问题开始

我们知道,超卖是由于没有考虑并发问题造成的,所以要加锁。那扣用户积分是不是也要考虑并发问题呢?答案是肯定的。但如果用synchronized(this)效率是极其低下的,我们想要的效果是每个用户拥有自己的锁,这样不同用户之间就互不影响了。实现如下:

public void buyGoodsBySync(Integer userId, int integral) {
    synchronized (userId) {
        log.info("获取到锁");
        User user = getById(userId);
        //减去积分
        user.setIntegral(user.getIntegral() - integral);
        updateById(user);
        log.info("释放锁");
    }
}

 这么写能实现想要的效果么?

答案是如果userId小于等于127能实现,大于127则不能实现。

要回答这个问题需要两个知识点,Integer的享元模式和synchronized的实现原理。

在[-128,127]之间,Integer会从IntegerCache中取,所以是同一个对象,超过127则不是同一个对象。

synchronized的实现原理

synchronized又叫对象锁,他只能把对象当成锁,所有java对象都有对象头,里面有个MarkWord区域,看下图,当Thread-2去获取锁时,会去obj的对象头的MarkWord区域看锁是否被占用,没有被占用则占用锁,并关联一个Monitor(又叫监视器或管程)对象,同时放入Owner中并计数,所以synchronized是可重入锁。这时Thread-1和Thread-3进来,发现锁被占用了,就放入EntryList中,进入blocked状态。等Thread-2处理完毕,系统随机在EntryList中选取一个线程占有锁并执行,因为并不是先进入等待队列就能优先获取锁所以synchronized是非公平锁。

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值