在多线程的程序中,JAVA为了具体的控制每个线程的,所以有了锁机制。所谓的显式锁和隐式锁,就是在使用的时候使用者是否需要手动写代码去获取锁和释放锁。显式锁使用Lock关键字,需要手动写代码去获取锁和释放锁。隐式锁使用synchronized修饰符,不需要手动写代码去获取锁和释放锁。
一、显式锁和隐式锁
1.隐式锁
隐式锁中又分为同步代码块和同步方法,但是都是基于Synchronized关键字来实现的,因为他只需要是使用管关键字就可以,不用显示加锁和解锁的过程,所以称之为隐式锁,具体的实现可以参考下面的代码:
同步代码块
public void method(){
synchronized(this){
//要锁住的代码,一次只能有一个线程来指向这段代码
}
}
上面的代码是同步代码块,就是在代码块前面加上synchroized关键字,并在后面的小括号内传入锁对象,这里的this是指定了当前的这个对象作为锁,注意任何对象都是可以作为锁来使用的。这个是排队执行,一个线程进入代码块时,就会把这个锁对象的状态变成上锁状态,其他的线程发现是上锁状态时,就会在外面等待,直到这个线程将锁住的代码块执行完毕之后,将锁对象的状态变为解锁,其他的线程才会一起抢,谁抢到就重复上面的操作,知道满足某个条件,程序结束。
同步方法
public synchronized void method(){
//方法体
}
同步方法就是将Synchroized关键字方放在方法的返回值前面,这里的锁就是也就是this,谁调用它,谁就是他的锁。原理跟同步代码块一样,但是这里的锁因为是this,如果在一个线程对象里有多个方法,那么第一个线程执行时给这个this上了锁,那么其他方法都是不能执行的。只有等一个方法执行完了之后,改变锁的状态,其他的才可以执行。
2.显式锁(Lock)
显式锁的概念是相对于隐式锁的,因为显式锁在使用的时候程序员可以控制上锁和解锁,所以称之为显式。显式锁是一个接口,它的实现类主要有三个,ReentrantLock 是其最主要的实现类,ReadLock 和 WriteLock 是 ReentrantReadWriteLock 内部定义的两个内部类,他们继承自 Lock 并实现了其定义的所有方法,精细化读写分离。而 ReentrantReadWriteLock 向外提供读锁、写锁。
public class Demo03 implements Runnable {
Lock l = new ReentrantLock();
@Override
public void run() {
l.lock();
try{
//要锁住的代码
}catch(Exception e){
//异常的处理逻辑
}finally{
l.unlock();
}
}
}
首先要在线程类里面定义一个锁对象,然后通过他的lock()方法来上锁,锁住的东西就是直到调用它unlock()方法开锁之前的所有代码,显式锁如果上锁,一定要记得在最后开锁,建议写在finally代码块里面。还要注意只有上了锁才能开锁,不上锁开锁系统会报异常。
3.两者的区别
(1)Synchronized是内部实现的,不需要人为控制,jvm会在内部自动改变锁的状态,而Lock是需要上锁和解锁的,而且只上锁不解锁或者只解锁不上锁都是不可以的。
(2)Synchronized是针对代码块来上锁的,就是如果代码运行到同步代码块或者同步方法外面,锁就会自动解开。而Lock是针对于一个对象,不论你有多少的代码,只要上锁之后没有用unlock解锁,这个东西都是被锁住的,而且还会有异常,程序员还要对异常进行处理。这个虽然麻烦,但是他也提供了一个便利,就是开锁和解锁不必在同一个代码块里面,就增加了可操作性。
(3)Synchronized 关键字结合对象的监视器,JVM 为我们提供了一种“内置锁”的语义,这种锁很简便,不需要我们关心加锁和释放锁的过程,我们只需要告诉虚拟机哪些代码块需要加锁即可,其他的细节会由编译器和虚拟机自己实现。可以将我们的“内置锁”理解为是 JVM 的一种内置特性, 所以一个很显著的问题就是,它不支持某些高级功能的定制,比如说,我想要这个锁支持公平竞争,我想要根据不同的条件将线程阻塞在不同的队列上,我想要支持定时竞争锁,超时返回,我还想让被阻塞的线程能够响应中断请求等等。这些特殊的需求是“内置锁”满足不了的,所以在 JDK 层面又引入了“显式锁”的概念,不再由 JVM 来负责加锁和释放锁,这两个动作释放给我们程序来做,程序层面难免复杂了些,但锁灵活性提高了,可以支持更多定制功能,但要求你对锁具有更深层次的理解。
二、公平锁与非公平锁
1.公平锁:表示线程获取锁的顺序是按照线程启动顺序来获取的,即先来先得、先进先出。
非公平锁:表示获取锁是随机获得的,先启动的也不能保证一定先获得锁。
2.公平锁与非公平锁的区别:
(1)公平锁的性能要比非公平锁的性能要低。
(2)ReentrantLock类默认的构造参数为false也就是默认是非公平锁。