提到并发编程大多数第一时刻想到的就是synchronized同步锁了,synchronized也是面试中问的比较多的一个问题。在之前的文章中我们提到过线程安全的三个特性:原子性、可见性和有序性,并且说到了java中定义了一个关键字synchronized对于线程的这三个特性都实现了,这么说来synchronized关键字是可以保证线程安全的,那么如何使用synchronized来实现线程安全?它又是怎么样的一个实现原理呢?这篇文章我们将从下面的几个内容来聊聊synchronized这个关键字。
1.synchronized介绍
synchronized是java中的一个关键字,翻译成汉语是同步的意思,它的作用呢就是被其修饰的方法或者代码块在同一时刻只能有一个线程进行访问和执行,只有当该线程执行完毕之后其他的线程才可以进行竞争访问,并且当前访问的线程可以重复的申请竞争访问资源。
可以想象为大家都在一个窗口买东西,同一时刻只能有一个人在买,其他人都在等待,不一样的是外面等待的人并不会排好队而是都在等着正在买东西的人买完之后争夺到买东西的机会,并且现在买的人买完之后还能申请继续争夺买东西的机会。
简单来说:synchronized可以修饰代码块和方法,它可以保证同一时刻只能有一个线程访问被修饰的代码块或者方法,从而保证了线程的安全。synchronized犹如一把锁,当一个线程访问之后就锁定访问的共享资源代码段,达到互斥的效果,从而保证了线程的安全,并且同一个线程可以获取同一把锁多次,达到可重入的效果。
· synchronized特性
synchronized具有原子性、可见性、有序性和可重入性;
原子性
之前文章说到过,JVM中定义的8种原子性操作中的lock和unlock就是把非原子性操作变成原子性操作,例如a+=1为非原子性操作。JVM中使用的两个字节码指令monitorenter和monitorexit来实现lock和unlock操作,但是在java代码中没有直接操作JVM指令的,而是把这两个指令都封装到了synchronized关键字中来实现原子性操作。(讲解synchronized原理的时候会看到monitorenter和monitorexit指令封装)
可见性
synchronized保证有序性是因为unlock解锁操作之前必须把工作内存中数据同步回主内存来实现的;而主内存是所有线程都可以访问的共享内存,所以修改之后其它线程操作该数据时都可以看到被修改后的值。
有序性
synchronized实现有序性是因为当一个共享资源变量被lock锁定操作之后,同一时刻只能被一个线程使用,而单线程执行代码是没有指令重排等问题的,所以线程也是有序的。同样被lock锁定的共享资源排斥其他线程访问所以Synchronized也具有互斥性。
可重入性
synchronized的可重入性就是当一个线程调用synchronized代码持有对象锁的时候,如果调用了该对象的其他synchronized代码,那么可以重新持有该锁,即同一个线程可以获取同一把锁多次,所以synchronized具有可重入性。
2.synchronized的使用
synchronized同步锁主要分两种,一种是对象锁,另外一种是类锁;
· 对象锁
对象锁顾名思义锁的作用对象是实例对象,当synchronized修饰普通的方法或者代码块的时候,都可以指定锁的对象。因一个类可以有很多对象,所以对象锁是可以有多个的。
修饰普通方法&#