谈谈synchronized

为何要用synchronized关键字:

  synchronized是java的一种内部锁,是一种排他锁,一般也被称为悲观锁,它可以保障原子性,可见性,有序性。java

  当多个线程去调用同一个方法的时候,若是不用加synchronized锁,就可能出现线程不安全的问题。举个经典的例子,好比两夫妻一个用银行卡,一个用网银同时取同一个帐户的钱,安全

取钱这个操做在银行的后台确定是一个方法,若是两方同时调用,颇有可能形成取了两份的钱,这样确定是不行的。性能

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代码块中又调用了另一个加锁的方法,原本若是锁没有释放,是不能拿到锁的。可是可重入锁是能够的,系统会自动识别。

synchronized的底层实现:

  jdk早期的时候,synchronized的底层实现是重量级的,重量到可能须要到操做系统去申请锁的地步,因此形成synchronized的效率很是低。jdk1.5以后进行了改进,有了锁升级的概念。

当咱们访问synchronized的时候,HotSpot的实现是这样的,当第一个线程来访问的时候,先在锁对象的头上markword记录这个线程,实际上只要一个线程来访问的时候,是不会加锁的,

只是记录这个线程ID,此时称之为偏向锁

  偏向锁若是有线程竞争的话,好比我第一个线程尚未释放锁,第二个线程又来了,就会自动升级为自旋锁,自旋锁的实现原理就是,线程会一直转圈等待获取锁,若是转圈十次以后,尚未获取到锁

就自动升级为重量级锁

  因此说从效率方面来说,CAS(后续文章会讲解)并非必定就比synchronized锁的效率高,理解synchronized的底层实现,咱们就能够获得以下结论:

  • 被锁住的代码,执行实际短,线程数量少的状况,用CAS。
  • 被锁住的代码,执行时间长,线程数量多的状况,用系统锁(synchronized内部锁和lock显示锁)。

  为何这样说呢,假如我有1000个线程,用CAS自旋,那岂不是有999个线程会一直在旋转等待,这样是很是消耗资源的。

相关文章
相关标签/搜索