关于synchronized关键字,网上查询了很多的资料,有很多的说法,有的感觉甚至都没有说出个所以然,然后就直接跳过了,有的感觉都没有说到那个可以让人理解的理由,什么类锁,对象锁,全局锁,还有人说问锁定的是对象还是代码块,说的感觉让人很专业化,很复杂,但是还是不明白是怎么一回事,说的不全面,不具体,羞涩难懂。网上的各种说法真的是很多,越看越让我摸不着头脑。
最后还是觉得经过自己的运行测试比较靠谱一点:
synchronized其实锁定的可以是任何资源(对象,基本数据类型变量,类....),关于synchronized(this),synchronized(xx.class),synchronized方法,static synchronized方法,其实都是通过锁定的资源是否是同个资源,谁先抢到这个锁(锁定的资源),谁就先执行synchronized大括号内的这一段代码,关键就在于锁定的资源是否是一样的。跟什么多少个实例,全局锁什么的统统都没有关系。
锁定的对象就比如:
synchronized(this),this就是当前对象,synchronized方法和synchronized(this)代码块是一样的,只不过是synchronized作用的范围不一样而已。
synchronized(xx.class),xx.class就是锁,static synchronized方法和synchronized(xx.class)代码块也是一样的,只是作用的范围不一样而已。
下面贴一下程序运行的代码和结果:
synchronized(this),synchronized锁定的this对象,即TicketConsumer实例对象只有一个,两个线程使用的是同一把锁(ticketConsumer对象,锁的HashCode都为:1417180225),所以synchronized能起到控制多线程同步安全的作用。接下来,稍微做一下改动。
可以从结果看到,synchronized已经没有起到多线程同步安全的作用了,因为synchronized锁定的对象为str,每次调用run局部方法的时候都会重新创建一个实例对象s,锁定的不是同一个对象,锁的HashCode也一直在变,很明显,所以就不起作用了。接下来,再稍微做一下改动。
synchronized能起到控制多线程同步安全的作用,有的人也许会问,str不是每次调用run局部方法的时候也会重新创建吗?这个因为是String类型,和StringBuffer是有区别的,有了解的人就知道,String数据类型是保存在常量池的,重新创建,引用的是常量池的同一个对象,锁的HashCode也一直没变,synchronized锁定的依然是一个共享资源,谁先抢到谁先执行。接下来,再稍微做一下改动。
可以看到,synchronized能起到控制多线程同步安全的作用,之所以可以,是因为每个类都有唯一的字节码,锁定的是同一个资源,同一把锁。至于synchronized修饰方法,就不贴过程了,和同步块是一样的,只是作用的范围不同,synchronized方法就是相当于synchronized(this),static synchronized方法就相当于synchronized(该类.class)。
以上输出结果为true,可以看到,classs和classi的引用值是相等的,引用的是同一个对象。
接下来,再贴一个过程:
可以从结果看到,synchronized已经没有起到多线程同步安全的作用了,以Integer类型对象作为锁,并且不断的进行减一,锁的HashCode也一直在变,具体原因参考当Synchronized遇到这玩意儿,有个大坑,要注意!这篇文章,大致原因就是因为减一的操作会创建一个新的Integer类型对象,这时锁就改变了。不过一般正常情况下也不会有人拿这个票数去作为锁。接下来,再稍微做一下改动。
可以从结果看到,synchronized已经没有起到多线程同步安全的作用,我想原因跟上面的也是一样,在强制转换的过程中创建了一个新的Integer类型对象作为锁,锁的HashCode也一直在变。