Java中synchronized的参数怎么传?锁何时会失效?

1、java中为什么要用锁?

简单的一句话:主要为了防止高并发带来的数据不一致的问题。
举个例子1:假设数据库中有数据 : 2022-07-19-01,这个标识,接下来的美生成一条数据,我想基于前面一条数据+1。那么正确的数据是2022-07-19-02。如何拿到这个2022-07-19-01 数据呢?我们可能要查某个数据库又或者从线程中拿到这个数据。
这时候问题来了。。。假设同时10个人都想生成这个数据,大家都查到了数据是 2022-07-19-01,那么正常的话肯定会生成10个2022-07-19-02。
很明显,这不是我们想要的数据。于是,有了锁的概念,在生成数据的时候直接加锁,防止生成重复的数据。
但是之前查询出来的都是一样的数据如何保证呢???可以在加锁生成完之后可以再做一次校验,如果拿到的值与自己当前应该修改的值不符合固定,可以再做+1操作。这样能够避免上述问题。其实,可以在查询的时候就加锁,插入的时候也加锁,具体情况具体分析。因为加锁的操作量是很大的,不应该用很多的锁。

2.java中synchronized的参数怎么传?

通常我们可以传很多的参数,甚至可以是一个字符串,经常用的是类。但为什么要这么传呢?
首先我们要明白,锁这个玩意到底想干嘛?如何实现同步功能的呢?
举个例子:我们想实例化工具类中的一个对象,这样以后都不需要来实例化了。就像sping中的Bean都是单例的,你只管依赖注入,而不用每次都得new对象。

public class PPP {
   public Integer id;
   public String name;

    public PPP() {
    }
    
   public static RingRoute instance;
   public static RingRoute getInstance(){
       //我想这个PPP 类里面的RingRoute ,只生成一次
       if(instance ==null){
       //这里加了字符串作为锁
           synchronized ("sdasdas"){
               if(instance==null){
                   instance = new RingRoute();
               }
           }
       }
       return instance;
   }
}

接下来开启100个线程,看结果:

  public static void main(String[] args) {

        for (int i = 0; i < 100; i++) {
            start();
        }
    }

    public static void start() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                RingRoute instance = PPP.getInstance();
                //看地址有什么不同,说明生成得是不是唯一得实例
                System.out.println(System.identityHashCode(instance));
            }
        }).start();
    }

结果下图,只截出了部分:
在这里插入图片描述
这里把锁的对象换成 类名.class 也是可以的。说明instance都是一样得。

接下来换一种操作:

public static RingRoute getInstance(){
       String s = new String("123rweqrq");
       if(instance ==null){
       //每次锁我自己new的字符串对象
           synchronized (s){
               if(instance==null){
                   instance = new RingRoute();
               }
           }
       }

看结果:
在这里插入图片描述
总结:
第一种情况(锁生效):我们锁住的 类名.class或者字符串等等,这些都是在程序中需要被同步的,可以理解为共享资源(因为都是同一个地址)。当线程1进来了,发现锁了字符串:“sdasdas” ,那么线程1会率先拿到这个锁,接下来的线程2,3,4…进来了,也去找 “sdasdas”这个对象拿锁的时候,发现已经被人拿了,于是只能等待线程1释放锁了。才算实现了同步功能。

第二种情况(锁失效): 我们锁的是每次new 的字符串,当线程1,2,3…进来的时候,可能线程1跟线程2同时到达 String s = new String(“123rweqrq”);这行代码,但这个时候线程1和线程2所拿到的s对象已经不是相同的对象了(地址不一样),他们去找对应的s拿锁的时候,没人上锁,那我就直接执行后面的代码了。所以线程1跟线程2会返回不同的instance实例的地址。恰巧线程3在线程1后面,所以线程3会拿到线程1所创建好的instance,所以地址就跟线程1重复了。这也就是锁失效的场景。

第二种情况(锁失效):这种情况是在代码别处生成了instance实例,且没有加锁或者加锁对象与当前代码快的锁对象不是同一个的时候,这时候无法实现同步,即使当前代码块加锁了也没用。

因此在使用synchronized的时候,传入的参数也就是锁的对象需要是要同步的对象,也就是能够被共享的。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值