Static 和 Synchronized

这两天在定位一个网上问题的时候发现一个很诡异的现象,系统夜间的汇总任务跑了很长一段时间才能结束,而且日志显示这些汇总任务的每个子任务都很快就结束了,但整体任务还是耗费了很长一段时间才结束。

其实整体业务流程很简单,大致的流程就是系统创建了很多汇总任务,把它们丢到线程池中去执行。这些任务在执行的过程中,为了提高效率,会创建一些子任务并并发的运行它们,当子任务运行结束后,父任务就会结束,所以出现这种现象是非常不科学的。我的第一感觉就是是不是任务间存在不合理的锁竞争导致线程相互等待?仔细检查代码,果然发现了问题,在汇总任务的父类中有这样一个方法:

这个方法是汇总任务根据时间生成目标汇总时间周期用的,之所以会封装成一个方法,估计是为了代码复用考虑。封装本身并没有错,但是要命的是,开发人员将方法声明为static synchronized,让我们先回忆一下这个两个关键字的作用:

  • synchronized synchronized 关键字放在方法声明上时,表示该方法为Synchronized Methods,即同步方法,在The Java™ Tutorials中对同步方法有以下描述: First, it is not possible for two invocations of synchronized methods on the same object to interleave. When one thread is executing a synchronized method for an object, all other threads that invoke synchronized methods for the same object block (suspend execution) until the first thread is done with the object. Second, when a synchronized method exits, it automatically establishes a happens-before relationship with any subsequent invocation of a synchronized method for the same object. This guarantees that changes to the state of the object are visible to all threads. 简单来说就是当一个方法声明为同步方法的时候,不可能出现多个线程同时调用同一个对象(注意是同一个对象,这点很重要)上的该方法,只有当一个线程调用结束,其他线程才有可能获取锁并执行该方法。
  • static 在Java中static表示“全局”或者“静态”的意思,用来修饰成员变量和成员方法,当然也可以修饰代码块。被static修饰的成员变量和成员方法是独立于该类的,它不依赖于某个特定的实例变量,也就是说它被该类的所有实例共享。所有实例的引用都指向同一个地方,任何一个实例对其的修改都会导致其他实例的变化。

那么synchronized加上static会出现什么效果?按照上面的分析static是整个类共享的,不仅仅是一个对象,那么static synchronized修饰的变量、方法或者代码段就是在类的粒度上进行同步,而不是仅仅是在对象粒度上。对于这个问题,Java machine language specification中也有描述:

For a class (static) method, the monitor associated with the Class object for the method’s class is used.

For an instance method, the monitor associated with this (the object for which the method was invoked) is used.

所以在我们的业务代码中,如果在父类中声明了一个static synchronized的方法,就意味着每个继承它的子类及其对象在调用这个方法时都会争夺这个锁,那么造成任务执行效率低下也就是必然的了。

 

上面代码synchronized同时修饰静态方法和实例方法,但是运行结果是交替进行的,这证明了类锁和对象锁是两个不一样的锁,控制着不同的区域,它们是互不干扰的。同样,线程获得对象锁的同时,也可以获得该类锁,即同时获得两个锁,这是允许的。

 


结论:A: synchronized static是某个类的范围,synchronized static cSync{}防止多个线程中多个实例同时访问这个 类中的synchronized static 方法。它可以对类的所有对象实例起作用。

B: synchronized 是某实例的范围,synchronized isSync(){}防止多个线程中这一个实例同时访问这个类的synchronized 方法。

 

其实总结起来很简单。
一个锁的是类对象,一个锁的是实例对象。
若类对象被lock,则类对象的所有同步方法全被lock;
若实例对象被lock,则该实例对象的所有同步方法全被lock。

2.synchronized方法与synchronized代码快的区别
        synchronized methods(){} 与synchronized(this){}之间没有什么区别,只是synchronized methods(){} 便于阅读理解,而synchronized(this){}可以更精确的控制冲突限制访问区域,有时候表现更高效率。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值