Lock锁和Synchronized详解
java中存在两种形式的锁,在jdk1.5之前,一直使用Synchronized这个重量级锁,它是一个JVM层面,可重入的非公平重量级锁。而jdk1.5之后,引入了lock锁,Lock是一个用java实现的基于API层面、可重入的、可实现公平和非公平的锁。两种锁的作用是:解决因多线程对共享资源的操作产生的数据不一致性问题,保证了并发情形下对共享资源操作的可见性和一致性等问题。
Lock为接口,下面通过来比较他的一个实现类RetreentLock和Synchronized的相同和区别,然后下面详细解释每一个点。
锁类型 比较项 | Synchronized | ReentrantLock |
获得、释放锁情形 | 显示获得锁,隐式释放锁 | 显示的获得、释放锁 |
锁的级别 | JVM层面重量级锁 | API层面的锁 |
锁的类型 | 可重入、非公平、不可中断,强阻塞锁 | 可重入、公平\非公平、异步锁 |
锁状态 | 不可判断,不可响应中断 | 可判断,可响应中断 |
唤醒条件 | notify、notifyall | condition绑定多个条件 |
发生异常时 | 主动释放锁 | 必须在funally显示释放锁,否则,一直锁住资源 |
锁对象 | 修饰静态方法:类本身 修饰普通方法:类的实例 修饰代码块:建立的锁变量 | 通过AQS和CAS操作,实现线程锁的获取和释放 |
1. 都是用来协调多线程对共享对象、变量的访问 2. 都是可重入锁,同一线程可以多次获得同一个锁 3. 都保证了可见性和互斥性 |
关于锁对象
synchronized锁的锁对象
通过synchronized的用法我们可以知道。他可以修饰静态方法,普通方法和代码块。那么他的锁对象对应什么呢?
修饰静态方法:锁对象为类本身,所有的实例对象用的都是同一把锁。因为静态的在类加载的时候直接创建引用,并且只会被加载一次,它属于类本身,被该类的所有实例共享,所以只要是该类的实例,那么他的锁对象是同样一个,即是该类的字节码文件。
修饰普通方法:锁对象为类的实例对象,每一个实例拥有自己的锁对象。
修饰代码块:锁对象为自己定义的对象
比如:
Object o1=new Object(); synchronized (o1){ ........... }
Lock锁
Lock的实现类其实是没有锁对象的。他通过AQS、CAS操作来进行对共享资源的获取。具体的详细解释看下图。主要的获取锁操作在第2第3个函数。