锁的类型可分为四种:
1、可重入锁(synchronized和ReentrantLock):在执行对象中,所有方法不再获取锁。
2、可中断锁(synchronized是不可中断锁,Lock是可中断锁):在等待获取中可中断
3、公平锁:(ReentranLock和ReentranReadWriteLock):按等待获取线程的等待实际进行排队,等待时间长的优先获取锁。
4、读写锁:(ReadWriteLock和ReentrantReadWriteLock):对资源的处理可分成2个部分处理,读的时候可以多线程一起读,写的时候需要获取锁权限。
synchronized和Lock的区别:
类别 | synchronized | Lock |
---|---|---|
存在层次 | 在JVM上 | 是一个类 |
锁的获取 | 1、如果A线程获取锁,B线程会一直等待 2、如果A线程发生堵塞,B线程会一直等待 | 分情况而定,Lock有多个锁获取方式,大概就是尝试获得锁,线程不用一直等待(可通过tryLock判断有没有锁) |
锁的释放 | 1、线程执行完同步代码,释放锁 2、线程执行发生异常,jvm会让线程释放锁 | 在finally中必须释放锁,不然容易造成线程死锁 |
锁的状态 | 无法判断 | 可以判断 |
锁的类型 | 可重入、不可中断、非公平 | 可重入、可中断、可公平(非公平也可以) |
锁的性能 | 少量同步 | 大量同步 Lock可提高多线程的读操作效率(可以通过readwritelock实现读写分离) 在资源不是很激烈的情况下,synchronized锁的性能要优于ReetrantLock,但在资源竞争激烈的情况下,synchronized的性能将会下降几十倍,ReetrantLock的性能会维持常态。 ReetrantLock提供了多样化的同步。比如有时间限制的同步,可以被Interrupt的同步(synchronized的同步是不能Interrupt的)等。在资源竞争不激烈的情形下,性能稍微比synchronized差点点。但是当同步非常激烈的时候,synchronized的性能一下子能下降好几十倍。而ReentrantLock确还能维持常态。 |
synchronized
Synchronized方法锁、对象锁、类锁区别
synchronized,这个东西咱们通常称之为”同步锁“,他在修饰代码块的时候须要传入一个引用对象做为“锁”的对象。
jvm在修饰方法的时候,默认是当前对象做为锁的对象;
在修饰类时,默认是当前类的Class对象做为所的对象
故存在着方法锁、对象锁、类锁 这样的概念
方法锁(synchronized修饰方法时)
经过在方法声明中加入synchronized关键字来声明synchronized方法。
方法一旦执行,就会独占该锁,一直到从该方法返回时才将锁释放,此后被阻塞的线程方能得到该锁,从而从新进入可执行状态。
这种机制确保了同一时刻对于每个类的实例,其全部声明为synchronized的成员函数中之多只有一个处于可执行状态,从而有效避免了类成员变量的访问冲突。
对象锁(synchronized修饰方法或代码块)
当一个对象中有synchronized method或synchronized block的时候,调用此对象的同步方法或进入其同步区域的时候,必须先得到对象锁。
若此对象的锁被其它线程所调用了,就必须要等它释放锁才可调用。
java的全部对象都有一个互斥锁,这个锁由jvm自动获取和释放。
synchronized正常返回或抛异常而终止,jvm都会正常的释放锁。
1、方法锁形式参考:
public synchronized void sellTickets(){
int i =4;
while (i>0){
i--;
System.out.println(i);
}
}
2、代码块形式参考:
public void sellTickets2(){
int i =4;
synchronized (this){
while (i>0){
i--;
System.out.println(i);
}
}
}
类锁(synchronized修饰静态的方法或者代码块)
因为一个class不论被实例化多少次,其中的静态方法和静态变量在内存中都只有一份。因此,一旦一个静态的方法被声明为synchronized。此类全部的实例对象在调用此方法,共用同一把锁,咱们称之为类锁。
对象锁是控制实例方法之间的同步的,类锁是控制静态方法之间同步的。
类锁只是一个概念上的东西,并非真实存在的,他只是用来帮助咱们理解锁定实例方法和静态方法的区别的。
java类可能会有不少对象,可是只有一个Class(字节码)对象,也就是说类的不一样实例之间共享该类的Class对象。Class对象其实也仅仅是1个java对象,只不过有点特殊而已。
因为每一个java对象都有1个互斥锁,而类的静态方法是须要Class对象。因此所谓的类锁,只不过是Class对象的锁而已。
获取类的Class对象的方法有好几种,最简单的是[类名.class]的方式。(百度:获取字节码的三种方式)
类锁的两种方式
public static synchronized void sellTickets3(){
int i =4;
while (i>0){
i--;
System.out.println(i);
}
}
public void sellTickets4(){
int i =4;
synchronized (TestTime.class){
while (i>0){
i--;
System.out.println(i);
}
}
}
Lock接口
public interface Lock {
void lock();
void lockInterruptibly() throws InterruptedException;
boolean tryLock();
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
void unlock();
Condition newCondition();
}
lock()、tryLock()、tryLock(long time, TimeUnit unit)和lockInterruptibly()是用来获取锁的。
unLock()方法是用来释放锁的。