java线程高并发二:锁的知识

上文链接:java线程高并发提升一:基础知识回顾


1、java内存模型。

java内存具有可见性、原子性、有序性三种性质,相应性质讲解如下:
(1)可见性:是指线程之间的可见性,即一个线程修改的结果,另一个线程立即就能看到。比如:用volatile修饰的变量,就会具有可见性。在 Java 中 volatile、synchronized 和 final 实现可见性。
(2)原子性:原子性指的是不可分的操作。在 Java 中 synchronized 和ReentranLock的 lock、unlock 操作保证原子性。
(3)有序性:Java 语言提供了 volatile 和 synchronized 两个关键字来保证线程之间操作的有序性,volatile 是因为其本身包含“禁止指令重排序”的语义,synchronized 是由“一个变量在同一个时刻只允许一条线程对其进行 lock 操作”这条规则获得的,此规则决定了持有同一个对象锁的两个同步块只能串行执行。

j每个线程有自己的工作内存,工作内存包括局部变量(Local Variables)和主内存副本拷贝(Copy Memory),而多个线程之间共享资源通过主内存进行同步。
java线程高并发二:锁的知识
那么共享资源如何同步呢?
java线程高并发二:锁的知识
比如上题,定义资源a=0,在线程t1中操作将a变为1,在线程t2中操作将a变为2,结果显示a就算在t1中变为了1,在t2中也会变回0,可见上述过程中java内存对资源使用进行了重排,如何进行的重排呢?
Happens-before规则给出了解释:
java线程高并发二:锁的知识

2、synchronized关键字。

synchronized用来给方法或者类对象进行加锁的,控制方法或者对象在同一时间只能被一个线程占用,其主要解决多个线程同时访问的并发问题,保证线程安全。方法及对象上锁逻辑如下。

2.1 synchronized方法锁。

java线程高并发二:锁的知识
该例中锁在方法上,功能为单线程调用购买票数,结果为AB票数和为1000。需要注意点:每个使用synchronized的方法在javap反编译之后都具有一个ACC_SYNCHRONIZED标识(标识该方法正在被某个线程占用,其他线程需要等待),如果方法锁是static,那么锁作用在该类上,如果方法锁不是static,那么锁作用在同类的不同对象上(该类的不同对象互不关联)。

2.2 synchronized对象锁。

java线程高并发二:锁的知识
该锁是对象锁,作用结果同方法锁,需要注意点:与ACC_SYNCHRONIZED不同,对象锁使用monitorenter和monitorexit控制线程进出,当该对象锁处于monitorenter时,其他线程需等待。除了使用synchronized还可以使用ReentrantLock对对象上锁,如图展示ReentrantLock上锁取消锁及synchronized上锁取消锁过程。
java线程高并发二:锁的知识
synchronized与ReentrantLock的比较如下(S代表synchronized,R代表ReentrantLock):

相同点 不同点
S与R比较 均为上锁并控制单线程访问锁 S为Java关键字,R为Java sdk API级别锁;S可以为方法上锁,R不行;R可以通过方法tryLock 请求超时取消锁的资源,S不行;R有公平锁1和非公平锁,S只有非公平锁1

3、Volatile关键字

Volatile是Java语言关键字,也是指令关键字。其特点为:1、用来保证将最先变量值及时通知给其他线程,2、禁止volatile前后的程序指令进行重排序,3、不保证线程安全,不可用于数字的线程安全递增。其应用场景有:实时展示状态值;避免多线程中内存不可见而重复构建对象。


  1. 公平锁指A、B、C按时间先后顺序使用锁,非公平锁指A、B、C不按顺序的竞争锁。 ↩︎ ↩︎