一、什么是线程同步
线程同步机制是一套用于协调线程之间的数据访问的机制,该机制可以保障线程的安全
java平台提供的线程同步机制包括:锁,volatile关键字,synchronized关键字,final关键字,static关键字,以及相关api,如Object.wait()/notify()方法
二、什么是锁
线程安全问题的产生前提是多个线程并发访问共享数据
将多个线程对共享数据的并发访问(并行)转换为串行访问,即一个共享数据一次只能被一个线程访问,其他线程等待,锁就是复用这种思路来保障线程安全的。
锁(lock)可以理解为对共享数据进行保护的一个许可证,对于同一个许可证保护的共享数据来说,任何线程想要访问这些共享数据必须持有许可证,一个线程只有再持有许可证的情况下才能对这些共享数据进行访问,并且一个许可证一次只能被一个线程持有,许可证线程再结束对共享数据的访问后必须释放其持有的许可证
一个线程再访问共享数据时必须先持有锁,获得锁的线程称为锁的持有线程,一个锁一次只能被一个线程持有,锁的持有线程再获得锁之后 和释放锁之前这段时间所执行的代码称为临界区(critical section)
锁具有排他性(exclusive)即一个锁一次只能被一个线程持有。这种锁称为排他锁或者互斥锁(mutex)
jvm把锁分为内部锁和显示锁两种。内部锁通过synchronized关键字实现,显示锁通过concurrent包下的Lock接口的实现类实现
三、锁的作用
锁是通过互斥保障原子性,一个锁只能被一个线程持有,这就保证了临界区的代码一次只能被一个线程执行,使得临界区代码所执行的操作自然而然的具有了不可分割性,即具备了原子性。
可见性的保障是通过写线程冲刷处理器的缓存和读线程刷新处理器缓存这两个动作实现的
再Java平台中,锁的获得隐含着刷新处理器缓存的动作,锁的释放隐含着冲刷处理器缓存的动作
锁能够保障有序性,写线程再临界区锁执行的代码 再读线程所执行的临界区看来像是完全按照源码顺序执行的
tips:
使用锁保障线程的安全性,必须满足以下条件
1、这些线程在访问共享数据时必须使用同一个锁
2、即使是读取共享数据的线程也需要使用同步锁
四、锁的相关概念
1)可重入性
可重入性(reentrancy)是指如果一个线程在持有一个锁a的时候还能继续成功申请到该锁,那么我们就称这个锁为可重入锁,否则就是不可重入锁
2)锁的争用和调度
java平台中内部锁属于非公平锁,显示lock锁既支持公平锁也支持非公平锁
3)锁的粒度
一个锁可以保护的共享数据量大小称为锁的粒度
锁保护的共享数据量大,锁的粒度就粗,反之就细
锁的粒度果醋会导致线程在申请锁时会进行不必要的等待,锁的粒度过细会增加锁调度的开销
五、内部锁:synchronized关键字
java中的每个对象都有一个与之关联的内部锁,这种锁也称为监视器,这种内部锁是一种排他锁,可以保障线程的原子性,可见性,有序性
内部锁是通过synchronized关键字实现的,synchronized关键字可以修饰方法和代码块
修饰方法的语法:
public synchronized static void m1(){ }
修饰代码块的语法
public static void m1(){ synchronized (锁对象){ //代码块 .... } }
使用synchronized修饰的实例方法称为同步实例方法
使用synchronized修饰的静态方法称为同步静态方法
原文:https://www.cnblogs.com/brblog/p/12172168.html