我们需要先从线程来讲起,相关基本概念这里就不做过多的阐述,都太基本了,有需要可以参考:synchronized 相关概念。这里先从线程状态聊起
1、线程状态
线程共有 5 种状态:
- 新建状态:新建线程对象,并没有调用start()方法之前
- 就绪状态:调用start()方法之后线程就进入就绪状态,但是并不是说只要调用start()方法线程就马上变为当前线程,在变为当前线程之前都是为就绪状态。值得一提的是,线程在睡眠和挂起中恢复的时候也会进入就绪状态哦。
- 运行状态:线程被设置为当前线程,开始执行run()方法。就是线程进入运行状态
- 阻塞状态:线程被暂停,比如说调用sleep()方法后线程就进入阻塞状态
- 死亡状态:线程执行结束
2、锁类型
1、可重入锁:包含 synchronized 和 ReentrantLock,即在执行对象中所有同步方法不用再次获得锁。
2、可中断锁:Lock 为可中断锁,而 synchronized 并不是。即在等待获取锁的过程中是可以被中断的。
3、公平锁:ReentrantLock 和 ReentrantReadWriteLock 是公平锁,即按等待获取锁的线程等待时间进行获取,等待时间长的具有优先获取锁的权利
4、读写锁:ReadWriteLock 和 ReentrantReadWriteLock,对资源读取和写入的时候拆分成 2 部分处理,读的时候可以多线程一起读,写的时候必须同步地写。
具体区别为:
类别 | synchronized | Lock |
存在层次 | Java的关键字,在jvm层面上 | 是一个接口 |
锁的释放 |
1、以获取锁的线程执行完同步代码,释放锁 2、线程执行发生异常,jvm会让线程释放锁 |
在finally中必须释放锁,不然容易造成线程死锁 |
锁的获取 |
假设A线程获得锁,B线程等待。 如果A线程阻塞,B线程会一直等待 |
分情况而定,Lock有多个锁获取的方式,大致就是可以尝试获得锁,线程可以不用一直等待(可以通过tryLock判断有没有锁) |
锁状态 | 无法判断 | 可以判断 |
锁类型 | 可重入 不可中断 非公平 | 可重入 可判断 可公平(两者皆可) |
性能 | 少量同步 | 大量同步 1、Lock可以提高多个线程进行读操作的效率。(可以通过readwritelock实现读写分离) 2、在资源竞争不是很激烈的情况下,Synchronized的性能要优于ReetrantLock,但是在资源竞争很激烈的情况下,Synchronized的性能会下降几十倍,但是ReetrantLock的性能能维持常态; 3、ReentrantLock提供了多样化的同步,比如有时间限制的同步,可以被Interrupt的同步(synchronized的同步是不能Interrupt的)等。在资源竞争不激烈的情形下,性能稍微比synchronized差点点。但是当同步非常激烈的时候,synchronized的性能一下子能下降好几十倍。而ReentrantLock确还能维持常态。 |
如果想要了解 Lock 相关内容,请查看 Lock 详解