synchronized是java的一种内部锁,是一种排他锁,一般也被称为悲观锁,它可以保障原子性,可见性,有序性。java
当多个线程去调用同一个方法的时候,若是不用加synchronized锁,就可能出现线程不安全的问题。举个经典的例子,好比两夫妻一个用银行卡,一个用网银同时取同一个帐户的钱,安全
取钱这个操做在银行的后台确定是一个方法,若是两方同时调用,颇有可能形成取了两份的钱,这样确定是不行的。性能
1,synchronized加在方法上this
public class T { private int count = 10; public synchronized void m() { count--; System.out.println(Thread.currentThread().getName() + " count = " + count); } }
2,synchronized代码块spa
public class T { private int count = 10; public void m() { synchronized(this) { count--; System.out.println(Thread.currentThread().getName() + " count = " + count); } } }
这里两种方式达到的效果是同样的,咱们须要关注如下几点:操作系统
1,synchronized锁,锁的是什么东西。实际上是锁的一个对象,任意对象均可以(String常量,Integer,Long不能使用)。当一个线程拿到锁以后,其余的线程就只能等待当前线程执行完,线程
并释放锁以后,才能拿到锁并执行。以此来保证线程的安全。code
2,这两种方式咱们该用哪种呢?实际开发中,咱们应该用代码块的方式,为何要加锁,一般都是须要访问共享变量才会加锁,一个方法中并非全部代码都须要访问共享变量,对象
其余的业务逻辑是不须要加锁的,因此代码块的方式能够提升程序的性能。blog
3,synchronized是一种可重入的锁,什么意思呢,就是若是synchronized代码块中又调用了另一个加锁的方法,原本若是锁没有释放,是不能拿到锁的。可是可重入锁是能够的,系统会自动识别。
jdk早期的时候,synchronized的底层实现是重量级的,重量到可能须要到操做系统去申请锁的地步,因此形成synchronized的效率很是低。jdk1.5以后进行了改进,有了锁升级的概念。
当咱们访问synchronized的时候,HotSpot的实现是这样的,当第一个线程来访问的时候,先在锁对象的头上markword记录这个线程,实际上只要一个线程来访问的时候,是不会加锁的,
只是记录这个线程ID,此时称之为偏向锁。
偏向锁若是有线程竞争的话,好比我第一个线程尚未释放锁,第二个线程又来了,就会自动升级为自旋锁,自旋锁的实现原理就是,线程会一直转圈等待获取锁,若是转圈十次以后,尚未获取到锁
就自动升级为重量级锁。
因此说从效率方面来说,CAS(后续文章会讲解)并非必定就比synchronized锁的效率高,理解synchronized的底层实现,咱们就能够获得以下结论:
为何这样说呢,假如我有1000个线程,用CAS自旋,那岂不是有999个线程会一直在旋转等待,这样是很是消耗资源的。